netbirdio/netbird · error
failed to parse artifact private key: %w
Error message
failed to parse artifact private key: %w
What it means
Thrown by `signer sign-artifact` when reposign.ParseArtifactKey cannot decode the key supplied via the NB_ARTIFACT_PRIV_KEY env var or --artifact-key-file. The parser expects a single custom PEM block of type "ARTIFACT PRIVATE KEY" whose payload is JSON ({key, id, created_at, expires_at}) with a 64-byte Ed25519 private key (reposign/key.go:131-156). It fails on PEM decode failure, trailing PEM data, a wrong PEM type tag, bad JSON, or a wrong key length.
Source
Thrown at client/cmd/signer/artifactsign.go:136
var privKeyPEM []byte
var err error
if envKey := os.Getenv(envArtifactPrivateKey); envKey != "" {
// Use key from environment variable
privKeyPEM = []byte(envKey)
} else if privKeyFile != "" {
// Fall back to file
privKeyPEM, err = os.ReadFile(privKeyFile)
if err != nil {
return fmt.Errorf("read private key file: %w", err)
}
} else {
return fmt.Errorf("artifact private key must be provided via %s environment variable or --artifact-key-file flag", envArtifactPrivateKey)
}
privateKey, err := reposign.ParseArtifactKey(privKeyPEM)
if err != nil {
return fmt.Errorf("failed to parse artifact private key: %w", err)
}
artifactData, err := os.ReadFile(artifactFile)
if err != nil {
return fmt.Errorf("read artifact file: %w", err)
}
signature, err := reposign.SignData(privateKey, artifactData)
if err != nil {
return fmt.Errorf("sign artifact: %w", err)
}
sigFile := artifactFile + ".sig"
if err := os.WriteFile(artifactFile+".sig", signature, 0o600); err != nil {
return fmt.Errorf("write signature file (%s): %w", sigFile, err)
}
cmd.Printf("✅ Artifact signed successfully.\n")View on GitHub (pinned to 93e97f4bf1)
Solutions
- Confirm the input is the artifact key produced by `signer generate-artifact-key`: first line must be -----BEGIN ARTIFACT PRIVATE KEY----- and the file must contain exactly one PEM block
- If using NB_ARTIFACT_PRIV_KEY, export it preserving line breaks (e.g. NB_ARTIFACT_PRIV_KEY="$(cat artifact-key.pem)") or switch to --artifact-key-file
- Check the PEM body is intact: base64 lines unmodified and the embedded JSON parses (jq on the decoded block)
- Regenerate the key pair with generate-artifact-key if the file is suspected corrupted
Example fix
// before NB_ARTIFACT_PRIV_KEY=LS0tLS1CRUdJTi... ./signer sign-artifact --artifact-file netbird // after ./signer sign-artifact --artifact-key-file artifact-key.pem --artifact-file netbird
Defensive patterns
Strategy: type-guard
Validate before calling
pemData, err := os.ReadFile(keyFile)
if err != nil {
log.Fatalf("read key: %v", err)
} Type guard
func isArtifactPrivateKeyPEM(data []byte) bool {
block, rest := pem.Decode(data)
return block != nil && block.Type == "ARTIFACT PRIVATE KEY" && len(rest) == 0
} Prevention
- Only use keys produced by signer generate-artifact-key; never convert keys with openssl
- Store the PEM as a file artifact in CI (secret file) instead of a flattened env var so line breaks survive
- Name keys unambiguously: artifact-key-priv.pem vs root-key-priv.pem
When it happens
Trigger: Passing a ROOT PRIVATE KEY or a standard OpenSSL/SSH PEM instead of an artifact key; newlines stripped from the PEM when it is stored as a single-line CI secret in NB_ARTIFACT_PRIV_KEY (pem.Decode then fails); concatenating two PEM blocks (trailing-data check); hand-editing the JSON body inside the PEM.
Common situations: CI secret manager flattens the multi-line PEM to one line; release engineer picks the root key from the vault instead of the artifact key; an editor appends a second key block to the file.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- failed to parse artifact public key: %w
- failed to parse root public key(s): %w
- failed to parse private root key: %w
- sign artifact: %w
- artifact verification failed: %w
AI-assisted analysis of netbirdio/netbird@93e97f4bf1 (2026-08-16).
Data as JSON: /api/errors/9dc3396afa93591d.
Report an issue: GitHub.