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

  1. Regenerate the service account key in GCP and re-download the JSON file wholesale rather than editing the key string
  2. Inspect the wrapped %w cause: 'missing pem markers' means BEGIN/END lines are gone; 'base64 decode failed' means the body is corrupt
  3. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/7037bb535ee62972. Report an issue: GitHub.