router-for-me/CLIProxyAPI · error
missing pem markers
Error message
missing pem markers
What it means
From rebuildPEM, the recovery path that tries to reconstruct a PEM from damaged textual input: it searches for '-----BEGIN <KIND>-----' and '-----END <KIND>-----' and fails because one or both markers are absent, or END appears before BEGIN (keyutil.go:130-136). The kind is 'RSA PRIVATE KEY' only if that string appears, otherwise 'PRIVATE KEY'.
Source
Thrown at internal/auth/vertex/keyutil.go:135
if rsaKey, ok := key.(*rsa.PrivateKey); ok {
der := x509.MarshalPKCS1PrivateKey(rsaKey)
return &pem.Block{Type: "RSA PRIVATE KEY", Bytes: der}, nil
}
}
return nil, fmt.Errorf("private_key uses unsupported format")
}
func rebuildPEM(raw string) (string, error) {
kind := "PRIVATE KEY"
if strings.Contains(raw, "RSA PRIVATE KEY") {
kind = "RSA PRIVATE KEY"
}
header := "-----BEGIN " + kind + "-----"
footer := "-----END " + kind + "-----"
start := strings.Index(raw, header)
end := strings.Index(raw, footer)
if start < 0 || end <= start {
return "", fmt.Errorf("missing pem markers")
}
body := raw[start+len(header) : end]
payload := filterBase64(body)
if payload == "" {
return "", fmt.Errorf("private_key base64 payload empty")
}
der, err := base64.StdEncoding.DecodeString(payload)
if err != nil {
return "", fmt.Errorf("private_key base64 decode failed: %w", err)
}
block := &pem.Block{Type: kind, Bytes: der}
return string(pem.EncodeToMemory(block)), nil
}
func filterBase64(s string) string {
var b strings.Builder
for _, r := range s {
switch {View on GitHub (pinned to 78f0c4079e)
Solutions
- Restore the full PEM including BEGIN/END lines from the original GCP JSON file
- If reconstructing manually, wrap the base64 body: -----BEGIN PRIVATE KEY----- / body / -----END PRIVATE KEY----- with real newlines
- Re-download the service account key rather than hand-repairing it
Example fix
# before (markers lost) MIIEvQIBADANBgkqhkiG9w0BAQEFAASC... # after -----BEGIN PRIVATE KEY----- MIIEvQIBADANBgkqhkiG9w0BAQEFAASC... -----END PRIVATE KEY-----
Defensive patterns
Strategy: validation
Validate before calling
if !strings.Contains(pk, "-----BEGIN") || !strings.Contains(pk, "-----END") {
return fmt.Errorf("PEM markers missing from private_key")
} Prevention
- Always copy the complete PEM including BEGIN/END lines
- Use file transfer for keys instead of terminal paste
- Add a lint step that greps for markers in stored credentials
When it happens
Trigger: Key pasted without the BEGIN/END lines; footer missing because of truncation; only the base64 body retained; markers present for the other kind (e.g. 'RSA PRIVATE KEY' body but code looked for plain 'PRIVATE KEY' first and vice versa when only one flavor exists).
Common situations: Secret copied out of a JSON viewer that hid the header lines; CI truncating long env vars; users pasting only the 'middle' of the key assuming the rest is implied.
Related errors
- private_key is not valid pem: %w
- private_key pem decode failed
- private_key uses unsupported format
- service account missing private_key
- private_key invalid pkcs8: %w
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/90b71aac13b01b21.
Report an issue: GitHub.