DEV Community

Jordan Huang
Jordan Huang

Posted on

FAQ: A Green Trigger Job Is Not the Child Pipeline

Does a green trigger job mean the child passed?

I hear that claim in merge request threads weekly.

People treat the bridge like a normal test job.

What actually ran?

GitLab parent pipelines can start other pipelines.

You start those graphs with the trigger: keyword.

The parent then shows a bridge job instead.

The child runs inside another pipeline graph entirely.

So whose status actually sits on the merge request?

Why this FAQ exists

I keep seeing five claims repeated during rushed review.

They sound reasonable when the parent pipeline is green.

They collapse once you inspect the bridge payload itself.

Each myth below includes a check you can run today.

Myth 1: Green trigger means the child succeeded

Did the child pipeline even finish its jobs?

By default, GitLab can mark the trigger job earlier.

That success often means "downstream pipeline was created."

It does not mean "downstream pipeline already passed."

Read the current GitLab downstream-pipeline documentation first.

Add strategy: depend if the parent must wait.

Newer GitLab also documents strategy: mirror for tracking.

Check your instance before you copy either keyword blindly.

Evidence, not vibes

Look at the parent pipeline in the GitLab UI.

Open the trigger job, not only the child graph.

If it finished in seconds, it probably did not wait.

Then open the downstream pipeline as its own object.

Compare those two finished_at timestamps with your own eyes.

Example parent job

# parent: .gitlab-ci.yml
# Example only. Confirm strategy options on your GitLab version.

stages: [build, delegate]

pack:
  stage: build
  script:
    - echo "built" > dist.txt
  artifacts:
    paths: [dist.txt]
    expire_in: 1 hour

hand_off:
  stage: delegate
  trigger:
    include: child.yml
    # strategy: depend   # uncomment only after you read your docs
Enter fullscreen mode Exit fullscreen mode

That hand_off job is a bridge.

It is not a script: job on the parent.

It does not run your test suite by itself.

Myth 2: The child YAML in git is what ran

Is your child file even a static committed file?

Dynamic child pipelines use include:artifact on purpose.

The parent job writes YAML, then the child loads it.

Reviewers who only read child.yml can miss that hop.

A drafted child.yml can be unrelated to what executed.

Dynamic include sketch

# Example: generated child config, not a live production file.

emit_child:
  stage: build
  script:
    - python generate_child.py > generated-child.yml
  artifacts:
    paths: [generated-child.yml]

run_child:
  stage: delegate
  trigger:
    include:
      - artifact: generated-child.yml
        job: emit_child
    strategy: depend
Enter fullscreen mode Exit fullscreen mode

Ask one question before you approve the merge request.

Which job produced the YAML the child executed?

If nobody can answer, you still do not have a receipt.

Primary docs live under GitLab downstream pipelines and trigger:.

Myth 3: The child inherited every parent variable

Did you forward those variables on purpose, though?

Downstream pipelines do not receive a complete parent dump.

GitLab documents trigger:forward as the actual contract.

Those defaults have changed across GitLab versions before.

I do not treat memory as the current default value.

I open the docs for the GitLab version that is running.

# Example forwarding. Verify defaults on your GitLab.

hand_off:
  stage: delegate
  variables:
    DEPLOY_SHA: $CI_COMMIT_SHA
  trigger:
    include: child.yml
    strategy: depend
    forward:
      yaml_variables: true
      pipeline_variables: false
Enter fullscreen mode Exit fullscreen mode

Protected variables may still remain only on the parent.

Masked values should never appear inside any chat log.

The child job log is the only honest witness here.

Myth 4: Parent artifacts are already in the child

Where would those files sit in the child workspace?

A child pipeline is a separate pipeline object.

It does not auto-mount parent artifacts: paths for you.

GitLab has specific patterns for passing artifacts downstream.

needs inside one pipeline is not a bridge across graphs.

You need an explicit download, artifact include, or API fetch.

A check that fails closed

# verify_bridge.py — example auditor, not a GitLab runner.

import json
import sys


def main(path: str) -> int:
    data = json.loads(open(path, encoding="utf-8").read())
    jobs = data if isinstance(data, list) else data.get("bridges", [data])
    failures = []
    for job in jobs:
        name = job.get("name", "?")
        bridge_status = job.get("status")
        downstream = job.get("downstream_pipeline") or {}
        child_status = downstream.get("status")
        child_id = downstream.get("id")
        if bridge_status == "success" and child_status not in {"success"}:
            failures.append(
                f"{name}: bridge={bridge_status} child_id={child_id} child={child_status}"
            )
        if bridge_status == "success" and not child_id:
            failures.append(f"{name}: green bridge, missing downstream id")
    if failures:
        print("bridge/child mismatch:")
        print("\n".join(failures))
        return 1
    print("bridge statuses match recorded children")
    return 0


if __name__ == "__main__":
    raise SystemExit(main(sys.argv[1]))
Enter fullscreen mode Exit fullscreen mode

Save the GitLab bridges payload to disk first.

Then run the auditor against that saved JSON file.

Do not parse a chat summary of the pipeline status.

Myth 5: A free local session proved the hand-off

Can a laptop see your GitLab bridge objects?

I use drafting help. I do not outsource pipeline status.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

MonkeyCode offers free model access and a free server option.

That pairing is useful for YAML drafts and this auditor.

It is not a parent pipeline, child pipeline, or bridge job.

The server does not become your GitLab runner fleet.

The model does not hold CI_JOB_TOKEN for your project.

If I paste only the parent YAML, the child graph is missing.

If I paste a green unit test, the trigger strategy is missing.

Ask the session for a checklist, not a merge verdict.

Then run that checklist against GitLab itself.

Artifact: a one-hour verification workflow

This is the method I actually trust in review.

It needs one real pipeline, not a slide deck.

Link the GitLab docs beside the merge request, not folklore.

Useful starting points:

1. Capture the bridge, not the chat

# Example with glab. Replace IDs. Use a token you already own.

PROJECT_ID="123"
PARENT_PIPELINE_ID="987654"

glab api \
  "projects/${PROJECT_ID}/pipelines/${PARENT_PIPELINE_ID}/bridges" \
  > bridges.json

python verify_bridge.py bridges.json
Enter fullscreen mode Exit fullscreen mode

No glab on the machine? Use curl against the same REST endpoint.

Same JSON shape. Same auditor. Same failure mode.

# Example REST call. Host and IDs are yours to fill.

curl --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "$GITLAB_HOST/api/v4/projects/${PROJECT_ID}/pipelines/${PARENT_PIPELINE_ID}/bridges" \
  > bridges.json
Enter fullscreen mode Exit fullscreen mode

2. Decision table for the merge request

Print this table in the review, then fill the blanks.

Parent setup Green bridge means Still check
trigger: only Child pipeline was created Child status, manual jobs
strategy: depend Child finished; parent waited Which child, which ref
strategy: mirror Status should track the child Your GitLab version
include:artifact Generated YAML was included The artifact job, not git
forward: set You chose a variable contract Protected vars, empty values

A blank cell is a review blocker, not a style nit.

3. Child ref check

Did the child run the commit you think it ran?

Compare CI_COMMIT_SHA in both pipeline headers yourself.

For multi-project triggers, also compare the target project ref.

A green child on main does not bless this merge request.

4. Artifact presence check

# child.yml — example probe job

probe_inputs:
  stage: test
  script:
    - echo "child sha=${CI_COMMIT_SHA}"
    - test -f dist.txt && echo "parent artifact unexpectedly present" && exit 1
    - echo "no parent dist.txt mounted, as expected"
Enter fullscreen mode Exit fullscreen mode

That probe is mean on purpose during the first review.

It documents the isolation most trigger YAMLs quietly forget.

Remove the failure only after you add a real fetch path.

Corrected mental model

Treat trigger: as a message, not as a test job.

The bridge reports a contract you chose in YAML.

Creation, dependence, and mirroring are different contracts.

The child pipeline is a different object with its own id.

Variables, artifacts, and refs are separate contracts too.

A child pipeline and a multi-project pipeline are not twins.

One stays inside your project. The other crosses project boundaries.

A draft session can write YAML for either shape.

Only GitLab can instantiate the graph and store status.

Limitations

This FAQ does not replace instance-specific GitLab docs.

Self-managed GitLab often lags features. Check yours first.

strategy: mirror is version-sensitive, so read that page.

The auditor trusts the JSON file you actually saved.

Garbage payload in means garbage mismatch out later.

I am not claiming production incident counts or timings.

These are review habits, not a compliance evidence program.

Who should not use this approach

Do not use a chat verdict for protected production deploys.

Do not paste masked variables into any model session.

Do not skip strategy because a draft looked sequential.

If you need signed release evidence, use GitLab's own records.

If you cannot call the bridges API, stop at the UI compare.

A free server is the wrong place for customer secrets.

Teams without permission to read pipeline APIs should not fake the JSON.

What I want reviewers to ask

Which pipeline object is green on this merge request?

When did the bridge finish versus the child pipeline?

Which YAML file did the child actually load at runtime?

Which variables were forwarded on purpose, not by folklore?

Where did parent artifacts enter the child, if they entered at all?

If those answers are missing, the trigger job is not proof.

Draft help is fine. Status theater is not.

Want a second pass on the auditor script and YAML only? A MonkeyCode free session can review those files if tokens and job logs stay off the table.

Top comments (0)