Repository navigation
release: a published relay release builds no image because nostream@X.Y.Z is not a legal Docker tag #964
Description
What happened
Release nostream@3.7.0 was published on 2026-10-24. The Release workflow ran and its Build and push container image job failed at step 5:
ERROR: failed to build: invalid tag "ghcr.io/cameri/nostream:nostream@3.7.0": invalid reference format
No image was published for the release. The deploy path pulls :latest, so a host updating after this release keeps running the previous image, and nothing in the release says so.
Run: https://github.com/cameri/nostream/actions/runs/40095341397
Cause
.github/workflows/release.yml names three tag rules:
tags: |
type=match,pattern=nostream@(.+),group=1
type=ref,event=tag
type=raw,value=latesttype=ref,event=tag emits the git tag verbatim, and a changesets relay release is tagged nostream@3.7.0. A Docker tag must match [A-Za-z0-9_][A-Za-z0-9_.-]{0,127} — @ is not in that set, because it separates the repository path from the digest in an image reference. buildx therefore rejects the build, not just that one tag.
The match rule that derives 3.7.0 is correct. The defect is the ref rule, which cannot produce a legal tag for any changesets release.
Why it survived review
The workflow's own comment records how the block was verified: metadata-action's Meta class was run over it and returned 3.6.2, nostream@3.6.2 and latest. That confirms the strings the action emits; it does not confirm that Docker accepts them. The illegal one was in the output and was read as a third good tag.
Two documents state the same impossible tag, so they are part of the bug:
docs/CI-MIGRATION.mdoffersghcr.io/cameri/nostream:nostream@3.6.2as "published as-is from the release tag", and as a tag an operator may pin.docs/DEPLOYMENT.mdlists the published tags as{nostream@X.Y.Z, X.Y.Z, latest}.
Why it surfaced only now
Every earlier Release run was skipped: the job's old guard was if: startsWith(github.event.release.tag_name, 'v'), and gh run list --workflow=release.yml shows the runs for nostream@3.6.0, nostream@3.6.1, nostream@3.6.2 and nostream-website@1.3.0–1.3.2 as skipped. #944 widened the guard to accept nostream@, so this was the first time the workflow executed end to end, and the first chance the tag bug had to fire.
Also in the same block
type=raw,value=latest applies to prereleases as well, so publishing nostream@3.8.0-rc.1 would move latest onto a test build — and latest is what the deploy stacks pull.
Acceptance criteria
- A relay release run completes and pushes exactly the tags the documentation names, with no tag rejected by the registry.
- A prerelease publishes its version tag and does not move
latest. - A legacy
vX.Y.Zrelease still publishesX.Y.Z(andvX.Y.Z, if that form is kept for hosts that pinned it). - An illegal tag fails at the step that computes the tags, naming the offending tag, rather than at buildx with
invalid reference format. docs/CI-MIGRATION.mdanddocs/DEPLOYMENT.mdname only tags that the workflow actually publishes.
Activity
ci(release): publish legal image tags and keep latest off prereleases