OpenNHP/opennhp · error
failed to create config.json
Error message
failed to create config.json: %v
What it means
SaveZdtoConfig could not create (or truncate) the file `etc/ztdo/data-<doId>.json`. os.Create returned an error — the message text says "failed to create config.json" but it wraps the OS error from creating the ztdo data config. The DRG update is aborted.
Solutions
- Inspect the wrapped %v OS error and fix the cause (disk full: free space; permission: chown/chmod etc/ztdo).
- Confirm the filesystem containing ExeDirPath is writable at write time (mount options, rw remount).
- Validate the doId — reject/control excessively long or filesystem-illegal characters before persisting configs.
- Retry the DHP DRG operation once storage is healthy.
Example fix
// before: no guard on doId characters
configFileName := "data-" + objectId + ".json"
// after: sanitize before building the path
safeId := strings.Map(func(r rune) rune { if r=='/'||r=='\\'||r==0 {return -1}; return r }, objectId)
configFileName := "data-" + safeId + ".json" Defensive patterns
Strategy: try-catch
Validate before calling
dir := filepath.Join(exeDir, "etc", "ztdo")
os.MkdirAll(dir, 0o755)
if err := syscall.Access(dir, syscall.O_RDWR); err != nil {
return fmt.Errorf("ztdo dir not writable: %v", err)
} Type guard
func canCreateIn(dir string) bool {
p := filepath.Join(dir, ".probe")
f, err := os.Create(p)
if err != nil { return false }
f.Close(); os.Remove(p)
return true
} Try / catch
if err := SaveZdtoConfig(drg); err != nil && strings.Contains(err.Error(), "failed to create config.json") {
log.Error("ztdo write failed: %v — check disk space and permissions", err)
freeDiskOrRemount(); err = SaveZdtoConfig(drg)
} Prevention
- Monitor disk space on the volume hosting etc/ztdo.
- Keep doIds short and filesystem-safe; sanitize path characters.
- Alert on read-only remounts of the state volume.
When it happens
Trigger: HandleDHPDRGMessage → SaveZdtoConfig calls os.Create on a path in an unwritable directory, the disk is full, the path exceeds filesystem name limits (very long doId), or the name is invalid for the filesystem.
Common situations: Disk-full on the server volume hosting etc/ztdo; read-only mount after the earlier MkdirAll check raced with a remount; a doId containing characters illegal on the target filesystem.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- could not open file
- already exists, please delete it first
- could not open file
- error reading file
- file path cannot be empty
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/c8f07c336f6591e3.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/server/msghandler.go:740
if drgMsg.AccessUrl == "" { // provider update access url
drgMsg.AccessUrl = existingDrgMsg.AccessUrl
}
os.Remove(configPath)
}
// Make sure the etc directory exists
if err := os.MkdirAll(etcDir, 0755); err != nil {
return fmt.Errorf("failed to create etc directory: %v", err)
}
if _, err := os.Stat(configPath); err == nil {
return fmt.Errorf("%v already exists, please delete it first", configFileName)
}
file, err := os.Create(configPath)
if err != nil {
return fmt.Errorf("failed to create config.json: %v", err)
}
defer file.Close()
encoder := json.NewEncoder(file)
encoder.SetIndent("", " ")
return encoder.Encode(drgMsg)
}
// read data-<doId>.json to DRGMsg Object
func ReadZdtoConfig(doId string) (common.DRGMsg, error) {
etcDir := filepath.Join(ExeDirPath, "etc", "ztdo")
configFilePath := filepath.Join(etcDir, "data-"+doId+".json")
file, err := os.Open(configFilePath)
if err != nil {
return common.DRGMsg{}, fmt.Errorf("could not open file: %v", err)
}
defer file.Close()
View on GitHub (pinned to 6e04ca5ff0)