Skip to content
Latchkey LogoLatchkey home

No Docker tag has been generated by docker/metadata-action

No Docker tag has been generated is a warning from docker/metadata-action saying that none of its tag rules produced a version for the event that is running. It is a statement about the event and the tags input together, and it is never caused by leaving images out.

Default tag rules, the refs each one accepts, and where the version becomes empty
Each default rule tests github.ref against one regular expression. If every rule declines, version.main is never set and getTags returns an empty array.

What this error means

The metadata step is green. It writes two warnings, one about a version and one about a tag, and then sets tags and version to empty strings. The build step that reads them either pushes an image with no tag at all or fails a little later complaining about the tag it was handed. The two warnings always arrive together, which is worth knowing because they look like independent signals: the action computes a single version first and derives every tag from it, so an empty tag list and a missing version are the same event reported twice. The one that carries the diagnosis is the first.

Reconstructed from the two core.warning calls in docker/metadata-action src/main.ts (v6.2.0). Not captured from a run
Warning: No Docker image version has been generated. Check tags input.
Warning: No Docker tag has been generated. Check tags input.

A workflow that produces both warnings

This file is written for this page and has never been run. It replaces the action default tag rules with semver rules only, which is the common shape of a release pipeline, and then triggers on a push to a branch. On a branch push github.ref is refs/heads/main, no semver rule accepts it, and the action emits both warnings and two empty outputs.

The same file is correct on a tag push. That is what makes this hard to see in review: the workflow is not wrong, it is only wrong for the trigger it has.

.github/workflows/publish.yml (illustrative)
name: publish
on:
  push:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v7
      - id: meta
        uses: docker/metadata-action@v6
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
      - uses: docker/build-push-action@v7
        with:
          push: true
          tags: ${{ steps.meta.outputs.tags }}

Common causes

Your tag rules are all semver and the trigger is a branch

This is most of them. A release workflow is written for tag pushes, then gets a push: branches: trigger added for a staging build, and the semver rules decline the branch ref. Both warnings appear and the build pushes an untagged image. In our experience this is the version that survives review longest, because the file is correct for the trigger it was written for.

The event has no ref that any rule accepts

Every type=ref handler tests github.ref against one pattern and returns quietly when it does not match. On repository_dispatch, on a workflow_call invoked from an unusual context, or on any event where the ref is not under refs/heads, refs/tags or refs/pull, all three default rules decline in turn and the version is never set.

Every rule you declared is gated off by enable

The enable attribute is evaluated before the ref test, and a rule whose enable resolves to false is skipped entirely. A workflow that gates its tag rules on github.event_name or on a branch comparison can gate all of them off at once, which produces exactly the same two warnings as having no matching ref.

You replaced the defaults and dropped the fallback

Supplying any tags input at all replaces the four default rules rather than adding to them. A file that lists only the rules it cares about has no type=sha or type=raw underneath them, so there is nothing left to catch an event the listed rules do not cover.

How to fix it

Read the first warning, not the second

  1. Open the failed run and expand the metadata step.
  2. Find the Context info group at the top and read the ref: line it prints.
  3. Compare that ref against the three patterns in the table above.
  4. If no rule accepts it, the fix is a rule. If one should have accepted it, the fix is an enable attribute.

Add a rule that cannot decline

The cheapest correction is a tag type that does not test the ref at all. type=sha produces a short commit tag on every event, and type=raw produces whatever literal you give it. Either one guarantees the version is set, which guarantees the tag list is not empty, without changing what your existing rules do on the events they already handle.

.github/workflows/publish.yml (illustrative)
      - id: meta
        uses: docker/metadata-action@v6
        with:
          images: ghcr.io/${{ github.repository }}
          tags: |
            type=semver,pattern={{version}}
            type=semver,pattern={{major}}.{{minor}}
            type=ref,event=branch
            type=sha

Or keep the defaults and add to them

If you only needed semver on top of ordinary behavior, say so explicitly. Listing the four default rules alongside your own is more text but it is honest about what the file does, and it survives someone adding a new trigger later without reading the action source.

.github/workflows/publish.yml (illustrative)
          tags: |
            type=schedule
            type=ref,event=branch
            type=ref,event=tag
            type=ref,event=pr
            type=semver,pattern={{version}}

Make the empty case loud instead of silent

The action warns and continues, which is the wrong default for a publish job. Gate the push on the output being non-empty so an empty tag list stops the run rather than producing an image nobody can find. This is the only change here that turns a silent wrong result into a red job.

.github/workflows/publish.yml (illustrative)
      - id: meta
        uses: docker/metadata-action@v6
        with:
          images: ghcr.io/${{ github.repository }}
      - name: Fail if no tags were generated
        if: steps.meta.outputs.tags == ''
        run: |
          echo 'metadata-action produced no tags for ${{ github.ref }}' >&2
          exit 1

The version decides the tags, not the images input

Inside the action, getTags() opens with one test. If this.version.main is falsy it returns an empty array immediately, before it has looked at images at all. Only after that test does it ask for the image names, and when there are none it still builds tags, just without a registry prefix.

That branch is the reason a very common piece of advice about this warning is wrong. Leaving images out does not empty the tag list. It produces a list like main or 1.4.0 with no repository in front of it, which docker/build-push-action will happily accept and push somewhere you did not intend. An empty images input is a real bug with a different symptom, and this warning is not it.

docker/metadata-action, src/meta.ts (v6.2.0), condensed
public getTags(namesOnly?: boolean): Array<string> {
  if (!this.version.main) {
    return [];
  }
  ...
  const images = this.getImageNames();
  if (images.length > 0) {
    for (const imageName of images) {
      tags.push(...this.generateTags(this.version.main, imageName));
    }
  } else {
    tags.push(...this.generateTags(this.version.main));
  }

Which default rule accepts which ref

When tags is omitted entirely the action substitutes four rules of its own, in Transform: type=schedule, type=ref,event=branch, type=ref,event=tag and type=ref,event=pr. Each type=ref handler starts by testing this.context.ref against one regular expression and returns the version unchanged if it does not match, so a rule that does not apply is silent rather than noisy.

The table below is those three regular expressions read straight out of meta.ts. It is worth checking against your own trigger list before you change anything, because the fix is almost always to add one rule rather than to rewrite the ones you have.

Default ruleThe test it applies to github.refProduces a version on
type=ref,event=branch/^refs\/heads\//push to a branch, workflow_dispatch, schedule
type=ref,event=tag/^refs\/tags\//push of a tag, and the release event
type=ref,event=pr/^refs\/pull\//pull_request and pull_request_target
type=scheduleno ref test; the tag type must be schedulethe schedule event only

Why there is no recorded run on this page

Other failure pages in this area carry a log from a job somebody ran. This one has nothing a run could add. The decision the page is about is a pure function of two values the action already has in hand when it starts, github.ref and the tags input, and it is taken by four regular expressions you can read above. A recorded run would print the branch name back at you and then the same two warning lines that are quoted here from the source that writes them.

Nothing here is intermittent either. The same ref and the same input produce the same empty output every time, so there is no flake for a runner to retry and nothing for one to repair.

How to prevent it

  • Keep one rule that cannot decline, type=sha or type=raw, under every other rule.
  • Treat an empty steps.meta.outputs.tags as a failure in any job that pushes.
  • Re-read the tag rules whenever you add a trigger, not whenever a push breaks.
  • Pin docker/metadata-action to a major and move it deliberately, since the default rule set is part of the major.

Frequently asked questions

Does docker/metadata-action need the images input to produce tags?
No. Without images the action still generates tags, it just leaves off the registry prefix, so you get main instead of ghcr.io/owner/app:main. The tag list only comes back empty when no version was generated, which getTags tests for before it ever looks at the image names.
Why does metadata-action generate no tags on a branch push?
Because the rules you gave it do not accept a branch ref. type=semver and type=match read a tag, and type=ref,event=tag tests github.ref against /^refs\/tags\// and returns unchanged on anything else. Add type=ref,event=branch or type=sha and the branch push produces a version again.
What are the default tags for docker/metadata-action?
When the tags input is omitted the action substitutes type=schedule, type=ref,event=branch, type=ref,event=tag and type=ref,event=pr. Supplying any tags value replaces that list rather than extending it, which is why a file that lists only semver rules has no branch handling left.
Are the version warning and the tag warning two separate problems?
No, they are the same one printed twice. The action computes version.main first and warns if it is empty, then calls getTags(), which returns an empty array precisely when version.main is falsy and warns again. You will never see one without the other, so diagnose from the version.

Related guides

References

Tag rules cost nothing. The image build does. Latchkey runs it at $0.0025/min at 2 vCPU against $0.006. Start free → 30-day trial · No credit card