{"record":{"id":"d1f8646ba4922d4d","repo":"router-for-me/CLIProxyAPI","slug":"home-ca-fingerprint-is-required","errorCode":null,"errorMessage":"home ca fingerprint is required","messagePattern":"home ca fingerprint is required","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/home/certificate.go","lineNumber":191,"sourceCode":"\treturn nil\n}\n\nfunc verifyCACertificateFile(path string, expectedFingerprint string) error {\n\traw, errRead := os.ReadFile(path)\n\tif errRead != nil {\n\t\treturn errRead\n\t}\n\treturn verifyCACertificatePEM(raw, expectedFingerprint)\n}\n\nfunc verifyCACertificatePEM(raw []byte, expectedFingerprint string) error {\n\tactual, errFingerprint := certificateFingerprintPEM(raw)\n\tif errFingerprint != nil {\n\t\treturn errFingerprint\n\t}\n\texpected := normalizeFingerprint(expectedFingerprint)\n\tif expected == \"\" {\n\t\treturn fmt.Errorf(\"home ca fingerprint is required\")\n\t}\n\tif actual != expected {\n\t\treturn fmt.Errorf(\"home ca fingerprint mismatch\")\n\t}\n\treturn nil\n}\n\nfunc certificateFingerprintPEM(raw []byte) (string, error) {\n\tblock, _ := pem.Decode(raw)\n\tif block == nil || block.Type != \"CERTIFICATE\" {\n\t\treturn \"\", fmt.Errorf(\"home ca certificate pem is invalid\")\n\t}\n\tcert, errParse := x509.ParseCertificate(block.Bytes)\n\tif errParse != nil {\n\t\treturn \"\", errParse\n\t}\n\tsum := sha256.Sum256(cert.Raw)\n\treturn hex.EncodeToString(sum[:]), nil","sourceCodeStart":173,"sourceCodeEnd":209,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/home/certificate.go#L173-L209","documentation":"Thrown by verifyCACertificatePEM in internal/home/certificate.go when verifying the home CA certificate against an expected fingerprint. After computing the SHA-256 fingerprint of the PEM certificate, normalizeFingerprint(expectedFingerprint) trims/lowercases/strips colons; if the result is empty, the expected fingerprint was never supplied. The library refuses to trust a CA certificate without pinning it to a known fingerprint.","triggerScenarios":"Calling the certificate verification path (e.g. enroll/verify of the home CA) with an empty, whitespace-only, or colon-only expectedFingerprint value — typically because the config field that carries the fingerprint was left blank while ca-cert was set.","commonSituations":"Config yaml has home ca-cert path but no ca-fingerprint; operator copied the CA file but forgot to record its SHA-256; environment variable for the fingerprint unset in the deployment environment; fingerprint field renamed after a config schema change.","solutions":["Set the expected fingerprint in the home config (ca-fingerprint field) to the hex SHA-256 of the DER certificate: openssl x509 -in ca.pem -noout -fingerprint -sha256","Confirm the config file/env var actually loads (no typo in key name, .env present in working directory)","If fingerprints are managed out-of-band, ensure the enrollment flow stores the fingerprint before verification runs"],"exampleFix":"# before\nhome:\n  ca-cert: /etc/cliproxy/ca.pem\n\n# after\nhome:\n  ca-cert: /etc/cliproxy/ca.pem\n  ca-fingerprint: \"a1b2c3d4...\"  # sha256 of ca.pem","handlingStrategy":"validation","validationCode":"// before calling enrollment/verification, require a well-formed fingerprint\nfp := strings.ToLower(strings.ReplaceAll(strings.TrimSpace(cfg.CAFingerprint), \":\", \"\"))\nif len(fp) != 64 { // sha256 hex\n    return fmt.Errorf(\"home ca fingerprint missing or malformed: set it to sha256 hex of ca.pem\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Record the CA fingerprint at enrollment time in the same config management that distributes ca.pem","Validate config at startup: fail fast when ca-cert is set without ca-fingerprint"],"tags":["go","tls","certificate","configuration","home"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}