router-for-me/CLIProxyAPI · error

home ca certificate file is missing

Error message

home ca certificate file is missing

What it means

Consistency check in ensureHomeCertificateFiles: the client certificate and key files exist on disk, but the home CA certificate file is missing, so the mTLS triple is incomplete and the existing client material cannot be trusted/verified against the pinned fingerprint.

Source

Thrown at internal/home/certificate.go:136

func defaultCertificatePaths() (certificatePaths, error) {
	homeDir, errHome := os.UserHomeDir()
	if errHome != nil {
		return certificatePaths{}, errHome
	}
	dir := filepath.Join(homeDir, ".cli-proxy-api")
	return certificatePaths{
		Dir:        dir,
		ClientCert: filepath.Join(dir, "client-crt.pem"),
		ClientKey:  filepath.Join(dir, "client-key.pem"),
		CACert:     filepath.Join(dir, "home-ca-crt.pem"),
	}, nil
}

func ensureHomeCertificateFiles(ctx context.Context, claims homeJWTClaims, paths certificatePaths) error {
	if fileExists(paths.ClientCert) && fileExists(paths.ClientKey) {
		if !fileExists(paths.CACert) {
			return fmt.Errorf("home ca certificate file is missing")
		}
		if errVerify := verifyCACertificateFile(paths.CACert, claims.CAFingerprint); errVerify != nil {
			return errVerify
		}
		if errChmod := chmodCertificateFiles(paths); errChmod != nil {
			return errChmod
		}
		return nil
	}
	if errMkdir := os.MkdirAll(paths.Dir, 0o700); errMkdir != nil {
		return errMkdir
	}
	key, errKey := loadOrCreateClientKey(paths.ClientKey)
	if errKey != nil {
		return errKey
	}
	csrPEM, errCSR := createClientCSR(claims.CertificateID, key)
	if errCSR != nil {

View on GitHub (pinned to 78f0c4079e)

Solutions

  1. Delete ~/.cli-proxy-api/client-crt.pem and ~/.cli-proxy-api/client-key.pem and re-enroll so all three files are written together
  2. Or restore home-ca-crt.pem from backup and confirm it matches the ca_fingerprint in the enrollment token
  3. Check permissions/disk-full causes if enrollment keeps dying mid-write (files are written 0600)

Example fix

# before: partial state
~/.cli-proxy-api/client-crt.pem   # exists
~/.cli-proxy-api/client-key.pem   # exists
~/.cli-proxy-api/home-ca-crt.pem  # MISSING -> error

# after: re-enroll with a fresh token
rm ~/.cli-proxy-api/client-crt.pem ~/.cli-proxy-api/client-key.pem
# restart with the enrollment token; all three files are recreated
Defensive patterns

Strategy: validation

Validate before calling

func certTripleComplete(dir string) bool {
    for _, f := range []string{"client-crt.pem", "client-key.pem", "home-ca-crt.pem"} {
        if _, err := os.Stat(filepath.Join(dir, f)); err != nil {
            return false
        }
    }
    return true
}

Prevention

When it happens

Trigger: Under ~/.cli-proxy-api, client-crt.pem and client-key.pem exist but home-ca-crt.pem was deleted, never written (partial enrollment crash between file writes), or excluded by a backup/sync tool.

Common situations: A previous enrollment run was interrupted after writing some files, someone cleaned up 'unused' PEM files, or a dotfile-sync/backup tool skipped the CA file.

Understand the failure class

Related errors


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