{"record":{"id":"874ac39bf31225c6","repo":"OpenNHP/opennhp","slug":"failed-to-create-etc-directory-v-874ac3","errorCode":null,"errorMessage":"failed to create etc directory: %v","messagePattern":"failed to create etc directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/msghandler.go","lineNumber":731,"sourceCode":"\tconfigFileName := \"data-\" + objectId + \".json\"\n\n\tetcDir := filepath.Join(ExeDirPath, \"etc\", \"ztdo\")\n\tconfigPath := filepath.Join(etcDir, configFileName)\n\n\tif existingDrgMsg, err := ReadZdtoConfig(objectId); err == nil {\n\t\t// alway keep original date source type\n\t\tdrgMsg.DataSourceType = existingDrgMsg.DataSourceType\n\n\t\tif drgMsg.AccessUrl == \"\" { // provider update access url\n\t\t\tdrgMsg.AccessUrl = existingDrgMsg.AccessUrl\n\t\t}\n\n\t\tos.Remove(configPath)\n\t}\n\n\t// Make sure the etc directory exists\n\tif err := os.MkdirAll(etcDir, 0755); err != nil {\n\t\treturn fmt.Errorf(\"failed to create etc directory: %v\", err)\n\t}\n\n\tif _, err := os.Stat(configPath); err == nil {\n\t\treturn fmt.Errorf(\"%v already exists, please delete it first\", configFileName)\n\t}\n\n\tfile, err := os.Create(configPath)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to create config.json: %v\", err)\n\t}\n\tdefer file.Close()\n\n\tencoder := json.NewEncoder(file)\n\tencoder.SetIndent(\"\", \"  \")\n\treturn encoder.Encode(drgMsg)\n}\n\n// read data-<doId>.json to DRGMsg Object","sourceCodeStart":713,"sourceCodeEnd":749,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/msghandler.go#L713-L749","documentation":"SaveZdtoConfig could not create the ZTDO config directory `<ExeDirPath>/etc/ztdo`. os.MkdirAll failed (permissions, read-only filesystem, or a non-directory file at the path), so the data-<doId>.json config cannot be written and the DRG message handling fails.","triggerScenarios":"HandleDHPDRGMessage invokes SaveZdtoConfig while the server process lacks write permission on ExeDirPath, ExeDirPath is read-only (container rootfs), or a regular file named `etc` or `etc/ztdo` already exists blocking directory creation.","commonSituations":"Running nhp-serverd as a non-root user against a root-owned install directory; Kubernetes/Docker container with a read-only filesystem and no writable volume mounted at the exe path; accidental file created at the etc path.","solutions":["Ensure the directory containing the nhp-serverd binary is writable by the process user (chown/chmod or run under the service account that owns it).","If ExeDirPath/e tc exists as a file, remove or rename it so MkdirAll can create the directories.","In containers, mount a writable volume at the server's working/exe directory or disable the read-only rootfs.","Check SELinux/AppArmor policies that may block directory creation and add appropriate rules."],"exampleFix":"// before: binary installed root-owned, server runs as nhp\nsudo chown -R nhp:nhp /opt/opennhp\n// after: or pre-create the writable ztdo dir\nsudo mkdir -p /opt/opennhp/etc/ztdo && sudo chown nhp:nhp /opt/opennhp/etc/ztdo","handlingStrategy":"validation","validationCode":"dir := filepath.Join(exeDir, \"etc\", \"ztdo\")\nif fi, err := os.Stat(dir); err == nil && !fi.IsDir() {\n    return fmt.Errorf(\"%s exists and is not a directory\", dir)\n}\nif err := os.MkdirAll(dir, 0o755); err != nil {\n    return fmt.Errorf(\"cannot create %s: %v\", dir, err)\n}","typeGuard":"func ztdoDirWritable() bool {\n    d := filepath.Join(ExeDirPath, \"etc\", \"ztdo\")\n    os.MkdirAll(d, 0o755)\n    p := filepath.Join(d, \".writetest\")\n    if err := os.WriteFile(p, nil, 0o644); err != nil { return false }\n    os.Remove(p)\n    return true\n}","tryCatchPattern":"if err := publishZtdo(drgMsg); err != nil && strings.Contains(err.Error(), \"failed to create etc directory\") {\n    // fix perms or storage, then retry\n    fixStoragePermissions(); err = publishZtdo(drgMsg)\n}","preventionTips":["Run the daemon under a user that owns its install/exe directory.","Provision etc/ztdo in deployment scripts or mount a writable volume in containers.","Avoid read-only rootfs without an explicit writable volume for state."],"tags":["filesystem","permissions","directory"],"backgroundTag":"mkdir-permission-denied","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}