docker/cli · error

failed to sign

Error message

failed to sign %s:%s: %w

What it means

In PushTrustedReference (trust_push.go:139-146), after the target has been added and Publish() attempted, if any error remains it is wrapped as 'failed to sign <repo>:<tag>' and then passed through NotaryError for human-friendly mapping. This is the catch-all signing/publish failure for a trusted push - the underlying cause is in the wrapped error (could be ErrNoKeys, ErrInsufficientSignatures, network error during publish, etc.).

Solutions

  1. Read the wrapped (%w) underlying error first - it is mapped by NotaryError into a more specific message; address that root cause (e.g. import key if ErrNoKeys).
  2. Ensure a valid signing key for the targets/releases role is loaded locally ('docker trust key load').
  3. For delegation-based repos, confirm the pushing user holds one of the delegation keys whose ID is listed in the role's KeyIDs (check with 'docker trust inspect --pretty').
  4. Retry on transient network errors; if Publish partially uploaded metadata, the next attempt may need the server-side stale changelist cleared (clearChangeList is called in lookupTrustInfo).
  5. If initializing for the first time, confirm the root key passphrase (DOCKER_CONTENT_TRUST_ROOT_PASSPHRASE) is set.
Defensive patterns

Strategy: try-catch

Validate before calling

// Validate signing prerequisites before calling PushTrustedReference/Publish.
func preflightTrustedPush(repo client.Repository) error {
    if _, err := repo.ListTargets(); err != nil {
        // tolerate not-initialized/not-exist (PushTrustedReference bootstraps), surface the rest
        if _, ok := err.(client.ErrRepositoryNotExist); !ok && _, ok2 := err.(client.ErrRepoNotInitialized); !ok2 {
            return trust.NotaryError(gun, err)
        }
    }
    return ensureSigningKeyAvailable(repo, os.Getenv("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE"))
}

Try / catch

if err := repo.Publish(); err != nil {
    err = fmt.Errorf("failed to sign %s:%s: %w", gun, tag, err)
    return trust.NotaryError(gun, err) // maps underlying type to a human message
}

Prevention

When it happens

Trigger: repo.Publish() fails (network error uploading metadata to notary server); repo.AddTarget() / AddToAllSignableRoles() fails (no valid signing keys for delegation roles - 'no valid signing keys for delegation roles' from GetSignableRoles at trust.go:317); repo.Initialize() fails during first push; the underlying error is then mapped by NotaryError into one of the specific messages.

Common situations: First-time trusted push where repository initialization fails; CI environment without the signing key; delegation role configured but the pushing identity lacks any of the delegation keys; transient network error between client and notary server during the final Publish step; notary server out of disk or misconfigured.

Related errors


AI-assisted analysis of docker/cli@4f84911bfe (2026-08-07). Data as JSON: /api/errors/5843c5b5e4c018e6. Report an issue: GitHub.

Appendix: source

Thrown at cmd/docker-trust/internal/trust/trust_push.go:144

		// Initialize the notary repository with a remotely managed snapshot key
		if err := repo.Initialize([]string{rootKeyID}, data.CanonicalSnapshotRole); err != nil {
			return NotaryError(repoInfo.Name.Name(), err)
		}
		_, _ = fmt.Fprintf(ioStreams.Out(), "Finished initializing %q\n", repoInfo.Name.Name())
		err = repo.AddTarget(notaryTarget, data.CanonicalTargetsRole)
	case nil:
		// already initialized and we have successfully downloaded the latest metadata
		err = AddToAllSignableRoles(repo, notaryTarget)
	default:
		return NotaryError(repoInfo.Name.Name(), err)
	}

	if err == nil {
		err = repo.Publish()
	}

	if err != nil {
		err = fmt.Errorf("failed to sign %s:%s: %w", repoInfo.Name.Name(), tag, err)
		return NotaryError(repoInfo.Name.Name(), err)
	}

	_, _ = fmt.Fprintf(ioStreams.Out(), "Successfully signed %s:%s\n", repoInfo.Name.Name(), tag)
	return nil
}

View on GitHub (pinned to 4f84911bfe)