{"record":{"id":"4e96538185e009bb","repo":"OpenNHP/opennhp","slug":"could-not-open-file-v-4e9653","errorCode":null,"errorMessage":"could not open file: %v","messagePattern":"could not open file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/server/msghandler.go","lineNumber":755,"sourceCode":"\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\nfunc ReadZdtoConfig(doId string) (common.DRGMsg, error) {\n\tetcDir := filepath.Join(ExeDirPath, \"etc\", \"ztdo\")\n\tconfigFilePath := filepath.Join(etcDir, \"data-\"+doId+\".json\")\n\tfile, err := os.Open(configFilePath)\n\tif err != nil {\n\t\treturn common.DRGMsg{}, fmt.Errorf(\"could not open file: %v\", err)\n\t}\n\tdefer file.Close()\n\n\tfileContentByte, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn common.DRGMsg{}, fmt.Errorf(\"error reading file: %v\", err)\n\t}\n\n\tvar config common.DRGMsg\n\n\terr = json.Unmarshal(fileContentByte, &config)\n\tif err != nil {\n\t\treturn common.DRGMsg{}, fmt.Errorf(\"json parsing error: %s\", err)\n\t}\n\treturn config, nil\n}\n\n// HandleRelayForward processes a decrypted NHP_RLY message from the standard","sourceCodeStart":737,"sourceCodeEnd":773,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/msghandler.go#L737-L773","documentation":"ReadZdtoConfig could not open `etc/ztdo/data-<doId>.json`. The ZTDO config for the given data object ID does not exist or is unreadable, so the function returns an empty DRGMsg with this wrapped os.Open error. Callers (DAR/DAV handlers, SaveZdtoConfig's existence probe) treat a non-nil error as \"no config yet\".","triggerScenarios":"HandleDHPDARMessage or HandleDHPDAVMessage references a doId whose config file was never saved on this server, or the file is unreadable due to permissions; also fires inside SaveZdtoConfig when probing whether a config already exists.","commonSituations":"Client asks for a ZTDO on the wrong server (config was written on another node); server restarted with an empty volume so etc/ztdo is wiped; typo'd doId in the request.","solutions":["Verify the doId in the request matches an existing etc/ztdo/data-<doId>.json on this server (ls the directory).","Re-run the DHP DRG (publish) flow to create the missing ZTDO config before reading it.","If configs must survive restarts, mount a persistent volume at ExeDirPath/etc/ztdo.","Check file permissions on etc/ztdo and its contents for the server process user."],"exampleFix":"// before: reading without checking existence\nmsg, err := ReadZdtoConfig(doId)\n// after: probe first and handle the not-found path\nif _, statErr := os.Stat(filepath.Join(ExeDirPath, \"etc\", \"ztdo\", \"data-\"+doId+\".json\")); os.IsNotExist(statErr) {\n    return fmt.Errorf(\"ztdo %s not published on this server\", doId)\n}\nmsg, err := ReadZdtoConfig(doId)","handlingStrategy":"validation","validationCode":"p := filepath.Join(exeDir, \"etc\", \"ztdo\", \"data-\"+doId+\".json\")\nif _, err := os.Stat(p); os.IsNotExist(err) {\n    return fmt.Errorf(\"ztdo %q not published on this server\", doId)\n}","typeGuard":"func ztdoConfigExists(doId string) bool {\n    if doId == \"\" { return false }\n    _, err := os.Stat(filepath.Join(ExeDirPath, \"etc\", \"ztdo\", \"data-\"+doId+\".json\"))\n    return err == nil\n}","tryCatchPattern":"msg, err := ReadZdtoConfig(doId)\nif err != nil && strings.Contains(err.Error(), \"could not open file\") {\n    // treat as unpublished: fall back to re-publish flow\n    return republishZtdo(doId)\n}","preventionTips":["Verify the doId is routed to the server that holds its config.","Mount etc/ztdo on persistent storage so restarts don't lose configs.","Publish (DRG) before attempting DAR/DAV reads for a new ztdo."],"tags":["filesystem","config","not-found"],"backgroundTag":"file-not-found","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"}