{"record":{"id":"1eebdfb136debb60","repo":"caddyserver/caddy","slug":"loading-root-cert-v","errorCode":null,"errorMessage":"loading root cert: %v","messagePattern":"loading root cert: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddypki/ca.go","lineNumber":288,"sourceCode":"\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"initializing certificate authority: %v\", err)\n\t}\n\n\treturn auth, nil\n}\n\nfunc (ca CA) loadOrGenRoot() (rootCert *x509.Certificate, rootKey crypto.Signer, err error) {\n\tif ca.Root != nil {\n\t\trootChain, rootSigner, err := ca.Root.Load()\n\t\tif err != nil {\n\t\t\treturn nil, nil, err\n\t\t}\n\t\treturn rootChain[0], rootSigner, nil\n\t}\n\trootCertPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyRootCert())\n\tif err != nil {\n\t\tif !errors.Is(err, fs.ErrNotExist) {\n\t\t\treturn nil, nil, fmt.Errorf(\"loading root cert: %v\", err)\n\t\t}\n\n\t\t// TODO: should we require that all or none of the assets are required before overwriting anything?\n\t\trootCert, rootKey, err = ca.genRoot()\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"generating root: %v\", err)\n\t\t}\n\t}\n\n\tif rootCert == nil {\n\t\trootCert, err = pemDecodeCertificate(rootCertPEM)\n\t\tif err != nil {\n\t\t\treturn nil, nil, fmt.Errorf(\"parsing root certificate PEM: %v\", err)\n\t\t}\n\t}\n\tif rootKey == nil {\n\t\trootKeyPEM, err := ca.storage.Load(ca.ctx, ca.storageKeyRootKey())\n\t\tif err != nil {","sourceCodeStart":270,"sourceCodeEnd":306,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddypki/ca.go#L270-L306","documentation":"CA.loadOrGenRoot reads the root certificate PEM from Caddy storage (default path like storage/caddy/pki/<id>/ca/root.crt). If storage.Load fails with any error other than fs.ErrNotExist — permission denied, backend down, corrupt index — the error is wrapped as 'loading root cert'. A clean not-found instead triggers root generation, so this error means storage exists but is failing.","triggerScenarios":"storage.Load(ca.storageKeyRootCert()) returns a non-ErrNotExist error: unreadable file (mode/ownership), a failing custom storage module (Redis/S3/consul unreachable), or a filesystem I/O error on the default data directory. Raised during pki app provisioning.","commonSituations":"Running Caddy as a service whose data directory is owned by root while the process runs unprivileged; a custom storage backend outage at startup; read-only filesystem containers; NFS/overlay permission quirks.","solutions":["Fix storage access: chown/chmod the data storage directory (or bucket/prefix) so the Caddy process can read the CA assets; verify with sudo -u caddy cat <storage>/caddy/pki/.../root.crt.","If using a custom storage backend, restore connectivity/credentials and restart Caddy.","Verify the storage object is valid PEM and not truncated; restore from backup or delete the CA assets to regenerate if corrupt.","Set the storage path explicitly (storage file_system <dir>) to a writable location instead of relying on default directory resolution."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Pre-start: can the process actually read the CA root cert?\nif _, err := os.ReadFile(filepath.Join(dataDir, \"caddy\", \"pki\", caID, \"ca\", \"root.crt\")); err != nil && !errors.Is(err, fs.ErrNotExist) {\n    log.Fatalf(\"storage unreadable: %v\", err)\n}","typeGuard":null,"tryCatchPattern":"// storage hiccups are often transient; retry once after a delay, else fail loudly\nif err := startCaddy(cfg); err != nil {\n    if strings.Contains(err.Error(), \"loading root cert\") {\n        time.Sleep(2 * time.Second)\n        if err2 := startCaddy(cfg); err2 != nil { return err2 }\n        return nil\n    }\n    return err\n}","preventionTips":["Give the Caddy process ownership of its data directory from day one.","Probe custom storage backends (a cheap read) in container healthchecks before Caddy starts.","Mount persistent, writable storage explicitly in containers rather than defaulting to ephemeral paths."],"tags":["pki","storage","io","root-cert"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}