docker/cli · error

error: could not produce valid signature for

Error message

error: could not produce valid signature for %s.  If Yubikey was used, was touch input provided?: %v

What it means

Returned by NotaryError for signed.ErrInsufficientSignatures (trust.go:255-256). The client attempted to produce a signature but could not create a valid one - either no eligible signing key is available in the local store/crypto service, or a hardware-backed key (Yubikey) did not yield a signature because the required user-presence/touch input was not provided. The message explicitly prompts about Yubikey touch because that is the most common hardware cause.

Solutions

  1. If using a Yubikey, tap it when it flashes during the push operation and ensure pcscd (or the platform smart-card service) is running; retry the push.
  2. Confirm the required signing key is available: run 'docker trust key list' / 'notary key list' and verify a key for the targets/releases role exists.
  3. Import the correct private key with 'docker trust key load <key.file>' if it is missing from the local store.
  4. Set DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE correctly so an encrypted software key can be decrypted for signing.
  5. If the role needs a delegation key, add it via 'docker trust signer add' and ensure the signer publishes with that key.

Example fix

# before: Yubikey touch missed, push fails
DOCKER_CONTENT_TRUST=1 docker push myrepo/img:tag
# after: tap Yubikey when it flashes, ensure daemon running
sudo systemctl start pcscd
DOCKER_CONTENT_TRUST=1 docker push myrepo/img:tag  # tap Yubikey on prompt
Defensive patterns

Strategy: validation

Validate before calling

// Before publishing, confirm a usable signing key exists (incl. hardware-backed).
func ensureCanSign(repo client.Repository) error {
    if err := ensureSigningKeyAvailable(repo, os.Getenv("DOCKER_CONTENT_TRUST_REPOSITORY_PASSPHRASE")); err != nil {
        return err
    }
    // If a Yubikey is the backing store, verify pcscd/smart-card is reachable.
    if os.Getenv("DOCKER_TRUST_YUBIKEY") != "" {
        if err := checkYubikeyAvailable(); err != nil {
            return fmt.Errorf("Yubikey not ready for touch signing: %w", err)
        }
    }
    return nil
}

Type guard

func isErrInsufficientSignatures(err error) bool {
    if err == nil {
        return false
    }
    return errors.Is(err, signed.ErrInsufficientSignatures)
}

Try / catch

if err := repo.Publish(); err != nil {
    if errors.Is(err, signed.ErrInsufficientSignatures) {
        return fmt.Errorf("could not produce a valid signature: %w; if using a Yubikey, tap it when it flashes", err)
    }
    return trust.NotaryError(gun, err)
}

Prevention

When it happens

Trigger: During repo.Publish() or repo.AddTarget() when the signing operation needs a key that is either absent from the local key store or stored on a Yubikey that timed out waiting for touch. Also when the available signatures do not satisfy the role's signing requirements so the final signature set is insufficient to publish.

Common situations: User enabled DCT, the signing key is on a Yubikey, and during push the Yubikey LED blinked requesting touch but the user did not tap it within the timeout; Yubikey not plugged in or pcscd daemon not running; correct signing key never imported locally so no key can sign; role requires a delegation key that was removed.

Related errors


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

Appendix: source

Thrown at cmd/docker-trust/internal/trust/trust.go:256

		return fmt.Errorf("error: remote repository %s out-of-date: %v", repoName, err)
	case trustmanager.ErrKeyNotFound:
		return fmt.Errorf("error: signing keys for remote repository %s not found: %v", repoName, err)
	case storage.NetworkError:
		return fmt.Errorf("error: error contacting notary server: %v", err)
	case storage.ErrMetaNotFound:
		return fmt.Errorf("error: trust data missing for remote repository %s or remote repository not found: %v", repoName, err)
	case trustpinning.ErrRootRotationFail, trustpinning.ErrValidationFail, signed.ErrInvalidKeyType:
		return fmt.Errorf("warning: potential malicious behavior - trust data mismatch for remote repository %s: %v", repoName, err)
	case signed.ErrNoKeys:
		return fmt.Errorf("error: could not find signing keys for remote repository %s, or could not decrypt signing key: %v", repoName, err)
	case signed.ErrLowVersion:
		return fmt.Errorf("warning: potential malicious behavior - trust data version is lower than expected for remote repository %s: %v", repoName, err)
	case signed.ErrRoleThreshold:
		return fmt.Errorf("warning: potential malicious behavior - trust data has insufficient signatures for remote repository %s: %v", repoName, err)
	case client.ErrRepositoryNotExist:
		return fmt.Errorf("error: remote trust data does not exist for %s: %v", repoName, err)
	case signed.ErrInsufficientSignatures:
		return fmt.Errorf("error: could not produce valid signature for %s.  If Yubikey was used, was touch input provided?: %v", repoName, err)
	default:
		return err
	}
}

// AddToAllSignableRoles attempts to add the image target to all the top level
// delegation roles we can (based on whether we have the signing key and whether
// the role's path allows us to).
//
// If there are no delegation roles, we add to the targets role.
func AddToAllSignableRoles(repo client.Repository, target *client.Target) error {
	signableRoles, err := GetSignableRoles(repo, target)
	if err != nil {
		return err
	}

	return repo.AddTarget(target, signableRoles...)
}

View on GitHub (pinned to 4f84911bfe)