{"record":{"id":"f538866b3c4b1b13","repo":"caddyserver/caddy","slug":"making-folder-for-ca-database-v","errorCode":null,"errorMessage":"making folder for CA database: %v","messagePattern":"making folder for CA database: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddypki/acmeserver/acmeserver.go","lineNumber":285,"sourceCode":"\t\t}\n\t}\n\tif err != nil {\n\t\tif c := ash.logger.Check(zapcore.ErrorLevel, \"closing CA database\"); c != nil {\n\t\t\tc.Write(zap.String(\"db_key\", key), zap.Error(err))\n\t\t}\n\t}\n\treturn err\n}\n\nfunc (ash Handler) openDatabase() (*db.AuthDB, error) {\n\tkey := ash.getDatabaseKey()\n\tdatabase, loaded, err := databasePool.LoadOrNew(key, func() (caddy.Destructor, error) {\n\t\tdbFolder := filepath.Join(caddy.AppDataDir(), \"acme_server\", key)\n\t\tdbPath := filepath.Join(dbFolder, \"db\")\n\n\t\terr := os.MkdirAll(dbFolder, 0o755)\n\t\tif err != nil {\n\t\t\treturn nil, fmt.Errorf(\"making folder for CA database: %v\", err)\n\t\t}\n\n\t\tdbConfig := &db.Config{\n\t\t\tType:       \"bbolt\",\n\t\t\tDataSource: dbPath,\n\t\t}\n\t\tdatabase, err := db.New(dbConfig)\n\t\treturn databaseCloser{&database}, err\n\t})\n\n\tif loaded {\n\t\tif c := ash.logger.Check(zapcore.DebugLevel, \"loaded preexisting CA database\"); c != nil {\n\t\t\tc.Write(zap.String(\"db_key\", key))\n\t\t}\n\t}\n\n\treturn database.(databaseCloser).DB, err\n}","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddypki/acmeserver/acmeserver.go#L267-L303","documentation":"Returned by openDatabase when os.MkdirAll cannot create the ACME server's database folder under the app data dir ($AppDataDir/acme_server/&lt;key&gt;). This is an environment error — the process lacks permission, the path exists as a file, or the disk is full/read-only. It occurs inside a sync.OnceVec/databasePool LoadOrNew, so it surfaces as the provisioning error for acme_server.","triggerScenarios":"Caddy runs as an unprivileged user but XDG_DATA_HOME/~/.local/share/caddy is owned by root; the path component `acme_server` exists as a regular file; container with a read-only or full volume at the data dir; SELinux/AppArmor denying writes.","commonSituations":"systemd unit with DynamicUser or wrong User= after data was created by root during initial testing; Kubernetes emptyDir mounted read-only by mistake; Docker volume with wrong uid ownership (`chown 1000:1000` needed).","solutions":["Check the exact path in the wrapped error and run `ls -ld` on each parent — fix ownership with chown to the user running Caddy","Make sure no path component is a file: `rm` it if it blocks the directory","Give the volume write access (docker: not :ro; k8s: remove readOnly: true) and confirm disk space with `df -h`","If using a custom data dir, set XDG_DATA_HOME consistently across restarts so the same folder is reused"],"exampleFix":"# before\nsudo caddy run --config Caddyfile   # data dir created as root\nsystemctl start caddy               # runs as caddy user\n\n# after\nsudo chown -R caddy:caddy ~/.local/share/caddy\nsystemctl start caddy","handlingStrategy":"validation","validationCode":"// Verify the data dir is creatable/writable before enabling acme_server:\nfunc checkDataDir() error {\n    dir := filepath.Join(caddy.AppDataDir(), \"acme_server\")\n    if err := os.MkdirAll(dir, 0o755); err != nil {\n        return fmt.Errorf(\"cannot create %s: %w\", dir, err)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Own the data dir: run Caddy as the same user that created ~/.local/share/caddy","In containers, mount the data dir writable and size it adequately","Add a readiness probe that touches a file under the data dir"],"tags":["pki","acme","filesystem","permissions","environment"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}