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.

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.
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.
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
- Open the failed run and expand the metadata step.
- Find the Context info group at the top and read the
ref:line it prints. - Compare that ref against the three patterns in the table above.
- If no rule accepts it, the fix is a rule. If one should have accepted it, the fix is an
enableattribute.
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.
- 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=shaOr 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.
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.
- 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 1The 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.
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 rule | The test it applies to github.ref | Produces 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=schedule | no ref test; the tag type must be schedule | the 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=shaortype=raw, under every other rule. - Treat an empty
steps.meta.outputs.tagsas 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-actionto 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?
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?
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?
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?
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
- docker/metadata-action src/main.ts: the two warnings and the order they are written in
- docker/metadata-action src/meta.ts: getTags and the ref tests each rule applies
- docker/metadata-action src/tag.ts: the four rules substituted when tags is omitted
- The tags input reference, including every tag type and the enable attribute
- Docker documentation
- Docker build cache
- GitHub Actions documentation