router-for-me/CLIProxyAPI · error
private_key is not valid pem: %w
Error message
private_key is not valid pem: %w
What it means
Wrapped error from sanitizePrivateKey when the private_key content is not decodable as PEM and the recovery path rebuildPEM also failed (keyutil.go:63-70). The sanitizer normalizes line endings, strips ANSI escapes, and forces valid UTF-8 before attempting pem.Decode; when both direct decode and textual reconstruction fail, the key is unusable.
Source
Thrown at internal/auth/vertex/keyutil.go:70
}
clone["private_key"] = normalized
return clone, nil
}
func sanitizePrivateKey(raw string) (string, error) {
pk := strings.ReplaceAll(raw, "\r\n", "\n")
pk = strings.ReplaceAll(pk, "\r", "\n")
pk = stripANSIEscape(pk)
pk = strings.ToValidUTF8(pk, "")
pk = strings.TrimSpace(pk)
normalized := pk
if block, _ := pem.Decode([]byte(pk)); block == nil {
// Attempt to reconstruct from the textual payload.
if reconstructed, err := rebuildPEM(pk); err == nil {
normalized = reconstructed
} else {
return "", fmt.Errorf("private_key is not valid pem: %w", err)
}
}
block, _ := pem.Decode([]byte(normalized))
if block == nil {
return "", fmt.Errorf("private_key pem decode failed")
}
rsaBlock, err := ensureRSAPrivateKey(block)
if err != nil {
return "", err
}
return string(pem.EncodeToMemory(rsaBlock)), nil
}
func ensureRSAPrivateKey(block *pem.Block) (*pem.Block, error) {
if block == nil {
return nil, fmt.Errorf("pem block is nil")View on GitHub (pinned to 78f0c4079e)
Solutions
- Regenerate the service account key in GCP and re-download the JSON file wholesale rather than editing the key string
- Inspect the wrapped %w cause: 'missing pem markers' means BEGIN/END lines are gone; 'base64 decode failed' means the body is corrupt
- If storing via env var or secret manager, confirm newlines survive round-trip (compare sha256 of the decoded value with the original file)
Example fix
# before (key mangled into one line, markers lost) export SA_KEY="MIIEvQIBADANBg..." # after: keep the full PEM text with real newlines export SA_KEY="-----BEGIN RSA PRIVATE KEY-----\nMIIEvQ...\n-----END RSA PRIVATE KEY-----\n" # \n interpreted by the consumer
Defensive patterns
Strategy: validation
Validate before calling
pk := sa["private_key"].(string)
if !strings.Contains(pk, "-----BEGIN") || !strings.Contains(pk, "-----END") {
return fmt.Errorf("private_key lost PEM markers")
} Prevention
- Transport keys as whole files, not pasted strings
- Verify sha256 of key files after any transfer
- Prefer re-downloading from GCP over repairing mangled keys
When it happens
Trigger: private_key containing base64 garbage instead of a PEM block; a key truncated mid-copy so footer '-----END ... KEY-----' is missing; binary corruption; the key embedded with real literal '\n' escapes that still cannot be reconstructed; rebuildPEM failing because markers are absent or reversed.
Common situations: Copy-pasting keys through chat/email that mangles newlines; storing the key in YAML/env where '\n' escaping behaves unexpectedly; keys truncated by shell heredocs or column limits in secrets managers.
Related errors
- private_key pem decode failed
- private_key uses unsupported format
- missing pem markers
- private_key base64 decode failed: %w
- service account missing private_key
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/7037bb535ee62972.
Report an issue: GitHub.