Skip to content
DevOps AI ToolKit
Newsletter
All guides
AI for GitLab CI/CD By James Joyner IV · · 9 min read Last reviewed Jul 2026

GitLab CI Error Guide: 'downstream pipeline can not be created' — Fix Broken Trigger and Child Pipelines

Quick answer

Fix 'downstream pipeline can not be created' in GitLab CI: repair invalid child YAML, missing trigger files, empty jobs, ref/branch mismatches, and CI/CD variable errors so bridge jobs generate pipelines.

  • #gitlab
  • #ci-cd
  • #troubleshooting
  • #errors
Free toolkit

Stuck on this GitLab CI/CD error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

Overview

A trigger: job (a bridge) in GitLab does not run a script — it hands GitLab a configuration and asks it to create a downstream pipeline (a child pipeline in the same project, or a multi-project pipeline in another project). When GitLab accepts the config but cannot turn it into a real pipeline, the bridge job fails and the pipeline graph shows the downstream node in red with this message:

downstream pipeline can not be created

You will also see closely related variants surfaced on the bridge job or in the pipeline’s “Failed Jobs” tab:

The parent pipeline job could not create the child pipeline
config should contain at least one visible job
downstream pipeline can not be created, Ref is ambiguous

Unlike an invalid CI config error on the parent, this failure happens at the bridge — the parent pipeline started fine, but the generated or referenced child config is empty, invalid, or points at something that does not exist.

Symptoms

  • The bridge/trigger job shows a red “failed” status with no job log (bridges have no trace) or a one-line error.
  • The child pipeline node in the pipeline graph is missing or marked failed with downstream pipeline can not be created.
  • Dynamic child pipelines that worked yesterday fail after a refactor of the generator job.
  • Multi-project triggers fail while the same YAML works when run directly in the downstream project.
  • The generated artifact (e.g. generated-config.yml) is empty, zero-byte, or contains only comments/hidden jobs.

Common Root Causes

  • Empty or all-hidden child config — the generated/referenced YAML contains only hidden jobs (keys starting with .), templates, or comments. A pipeline needs at least one visible job.
  • Missing generated artifact — a dynamic child pipeline references a file the upstream generator job did not actually produce (wrong path, job failed silently, artifact expired or not passed via needs/artifacts).
  • Invalid child YAML — the generated config has a syntax error or references an undefined extends/include that only fails when GitLab compiles the child.
  • Bad include: in the childtrigger: include: points at a file that does not exist on the target ref.
  • Ref / branch mismatch — a multi-project trigger: targets a branch: or ref that does not exist in the downstream project.
  • rules produce no jobs — every job in the child config is filtered out by rules:/workflow:, leaving zero jobs to run.
  • Variable/forwarding errors — a variable expected by the child (used in rules: or an include) is never forwarded, so the child compiles to nothing.
  • Nesting/limit exceeded — child pipelines nested too deep, or downstream pipeline limits hit.

Diagnostic Workflow

1. Read the exact error on the bridge job. In the pipeline view, click the failed downstream node or open the “Jobs” tab and filter to the bridge. The suffix after the message (Ref is ambiguous, config should contain at least one visible job) tells you which cause below applies.

2. For dynamic child pipelines, verify the generator actually produced the file. The classic pattern — confirm the artifact path matches the trigger include path exactly:

generate-config:
  stage: build
  script:
    - ./scripts/generate-pipeline.sh > generated-config.yml
    # fail loudly if the generator produced nothing
    - test -s generated-config.yml || { echo "generated config is empty"; exit 1; }
  artifacts:
    paths:
      - generated-config.yml

run-child:
  stage: test
  needs:
    - job: generate-config
      artifacts: true
  trigger:
    include:
      - artifact: generated-config.yml
        job: generate-config
    strategy: depend

If the generator emits an empty file, add the test -s guard shown above so the generator fails clearly instead of the opaque bridge error downstream.

3. Validate the generated/child YAML with CI Lint. Copy the generated content and validate it. Use the CI Lint page (CI/CD → Editor → Validate, or the project’s /-/ci/lint) or the API:

# Validate a child config against the project, with variables expanded
curl --silent --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "https://gitlab.example.com/api/v4/projects/$CI_PROJECT_ID/ci/lint" \
  --data-urlencode "content@generated-config.yml" \
  --data "include_jobs=true" | jq '{valid, errors, merged_yaml}'

If valid is true but the pipeline still fails to create, look at merged_yaml — if there are no visible jobs after merge, that is your “at least one visible job” failure.

4. Confirm at least one visible job survives rules. A job whose every rule evaluates to when: never is dropped. Temporarily add an always-on job to prove the child can be created:

# Minimal known-good child config for isolation
smoke:
  stage: test
  script:
    - echo "child pipeline created successfully"
  rules:
    - when: always

If the child now creates, the problem is your rules:/workflow: filtering everything out — not the trigger wiring.

5. For multi-project triggers, check the target ref exists. A branch: that does not exist downstream yields Ref is ambiguous or a create failure:

deploy-downstream:
  stage: deploy
  trigger:
    project: my-group/deploy-project
    branch: main            # must exist in deploy-project
    strategy: depend

Verify the branch/tag actually exists in the downstream project and that the trigger has permission (the triggering user/token must be able to run pipelines there).

6. Check variable forwarding. If the child’s rules: or include: depend on a variable, forward it explicitly:

run-child:
  variables:
    DEPLOY_ENV: staging
  trigger:
    include: child/.gitlab-ci.yml
    forward:
      pipeline_variables: true

Example Root Cause Analysis

A monorepo used a dynamic child pipeline: a generate job wrote pipeline.yml containing one job per changed service. After a refactor, the bridge started failing with config should contain at least one visible job.

Diagnosis:

  1. The bridge job had no log, so the team ran CI Lint on the artifact — it reported valid: true but merged_yaml contained only a single hidden .service-template: job.
  2. Reading the generator script showed it emitted the shared .service-template anchor but, when no service directories changed, produced zero concrete jobs — leaving only the hidden template.
  3. On the MR that touched only README.md, the change-detection loop matched nothing, so the child had no visible jobs and GitLab refused to create it.

Fix: the generator now emits a fallback no-op job when nothing matches, and a test -s guard plus a visible-job assertion:

noop:
  stage: test
  script:
    - echo "No service changes detected; nothing to build."
  rules:
    - when: always

The bridge stopped failing because every generated config now contains at least one visible job. The team also added the CI Lint API call to the generator job so an invalid child config fails at generation time with a readable error.

Prevention Best Practices

  • Always guard generated configs with test -s generated-config.yml so an empty file fails the generator, not the bridge.
  • Emit a fallback no-op job in dynamic pipelines so the child never compiles to zero visible jobs.
  • Validate generated child YAML with the CI Lint API inside the generator job before triggering.
  • Match the artifact: path in trigger: include: exactly to the generator’s artifacts: paths: entry, and wire them with needs: [{ job:, artifacts: true }].
  • For multi-project triggers, pin and verify the downstream branch:/ref, and confirm trigger permissions.
  • Forward the variables the child needs with forward: pipeline_variables: true (or explicit variables:), and keep child rules: from filtering out every job.
  • Use strategy: depend so downstream failures propagate visibly instead of the parent going green while the child is broken.

Quick Command Reference

# Validate a child/generated config (variables + jobs expanded)
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "$CI_API_V4_URL/projects/$CI_PROJECT_ID/ci/lint" \
  --data-urlencode "content@generated-config.yml" \
  --data "include_jobs=true" | jq '{valid, errors}'

# Assert a generated config is non-empty (put in the generator job)
test -s generated-config.yml || { echo "empty child config"; exit 1; }

# List recent pipelines to find the failed bridge/child relationship
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "$CI_API_V4_URL/projects/$CI_PROJECT_ID/pipelines?order_by=id&sort=desc" | jq '.[0:5]'

# Check a downstream project's branches exist before triggering
curl -s --header "PRIVATE-TOKEN: $GITLAB_TOKEN" \
  "$CI_API_V4_URL/projects/<downstream-id>/repository/branches" | jq '.[].name'

Conclusion

downstream pipeline can not be created almost always means the child config GitLab was handed is empty, invalid, or points at something that does not exist — not that the trigger keyword is wrong. Read the exact suffix on the bridge job, validate the generated or referenced YAML with CI Lint, and confirm at least one visible job survives your rules:. Guarding generated configs against emptiness and adding a fallback no-op job eliminates the most common cause for good, so dynamic and multi-project pipelines create reliably every time.

Free download · 368-page PDF

Fixed it? Get 500 GitLab CI/CD & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.