{"record":{"id":"a329c80526655b82","repo":"OpenNHP/opennhp","slug":"failed-to-open-file-v","errorCode":null,"errorMessage":"failed to open file: %v","messagePattern":"failed to open file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"endpoints/db/utils.go","lineNumber":42,"sourceCode":"\n// NewDataPrivateKeyStore create a new DataPrivateKeyStore\nfunc NewDataPrivateKeyStore(providerPublicKeyBase64 string) *DataPrivateKeyStore {\n\treturn &DataPrivateKeyStore{\n\t\tProviderPublicKeyBase64: providerPublicKeyBase64,\n\t}\n}\n\n// NewDataPrivateKeyStoreWith create a new DataPrivateKeyStore with doId\nfunc NewDataPrivateKeyStoreWith(doId string) (d *DataPrivateKeyStore, err error) {\n\tetcDir := \"etc/ztdo\"\n\tfileName := \"data-key-\" + doId + \".json\"\n\n\tfullPath := filepath.Join(common.ExeDirPath, etcDir, fileName)\n\n\t// open and read all the content in file\n\tfile, err := os.Open(fullPath)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"failed to open file: %v\", err)\n\t}\n\n\tfileContentByte, err := io.ReadAll(file)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error reading file: %v\", err)\n\t}\n\n\td = &DataPrivateKeyStore{}\n\t_ = d.fromJson(fileContentByte)\n\n\treturn\n}\n\nfunc (d *DataPrivateKeyStore) Generate(mode ztdolib.DataKeyPairECCMode) (privateKey []byte) {\n\tecdh := core.NewECDH(mode.ToEccType())\n\td.DataPrivateKeyBase64 = ecdh.PrivateKeyBase64()\n\treturn ecdh.PrivateKey()\n}","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/db/utils.go#L24-L60","documentation":"NewDataPrivateKeyStoreWith loads a stored data private key file for a ZTDO from `<exeDir>/etc/ztdo/data-key-<doId>.json`. When os.Open fails - because the key file does not exist, the path is wrong, or the process lacks read permission - the store cannot be built and this wrapped error is returned to the caller (HandleUdpDataKeyWrappingOperations). The wrapped os error names the exact cause (e.g. 'no such file or directory').","triggerScenarios":"Calling NewDataPrivateKeyStoreWith(doId) when: (1) the key file was never created via Save() for that doId; (2) the file was deleted or the doId string is mistyped so the filename data-key-<doId>.json does not match; (3) the daemon's working/executable directory changed so common.ExeDirPath-based relative path etc/ztdo no longer resolves; (4) file permissions deny read access.","commonSituations":"Fresh deployment where keys were generated on another machine; running nhp-db from a different cwd or container path than when keys were saved; UUID/doId mismatch between caller and stored file; volume not mounted in Docker.","solutions":["Check the wrapped os error: if it is 'no such file or directory', verify the file exists at <exeDir>/etc/ztdo/data-key-<doId>.json and that the doId is correct.","Create the key first by constructing a store with NewDataPrivateKeyStore(...), calling Generate(mode), then Save(doId) before loading it.","Verify common.ExeDirPath matches where the keys were originally saved; restart the daemon from the expected directory or move the etc/ztdo directory.","Fix file permissions (chmod/chown) so the process user can read the key file."],"exampleFix":"// before: assumes the key file exists\nstore, err := db.NewDataPrivateKeyStoreWith(doId)\nif err != nil { return err }\n// after: generate and save on first use\nstore, err := db.NewDataPrivateKeyStoreWith(doId)\nif err != nil {\n\tif os.IsNotExist(errors.Unwrap(err)) {\n\t\tstore = db.NewDataPrivateKeyStore(providerPubB64)\n\t\tstore.Generate(ztdolib.ECCModeSm2)\n\t\tif err := store.Save(doId); err != nil { return err }\n\t} else {\n\t\treturn err\n\t}\n}","handlingStrategy":"try-catch","validationCode":"path := filepath.Join(common.ExeDirPath, \"etc/ztdo\", \"data-key-\"+doId+\".json\")\nif _, err := os.Stat(path); os.IsNotExist(err) {\n\t// key not yet created; generate and save first\n}","typeGuard":"func keyFileExists(doId string) bool {\n\tp := filepath.Join(common.ExeDirPath, \"etc/ztdo\", \"data-key-\"+doId+\".json\")\n\tst, err := os.Stat(p)\n\treturn err == nil && !st.IsDir()\n}","tryCatchPattern":"store, err := db.NewDataPrivateKeyStoreWith(doId)\nif err != nil {\n\tif errors.Is(err, fs.ErrNotExist) {\n\t\t// fall back to generating a new key\n\t} else {\n\t\treturn fmt.Errorf(\"loading data key for %s: %w\", doId, err)\n\t}\n}","preventionTips":["Always generate and Save the key before any code path that loads it.","Use absolute paths (resolve common.ExeDirPath once at startup) so cwd changes cannot hide key files.","Log the resolved full path in the error to make doId/path mismatches obvious.","Mount etc/ztdo as a persistent volume in containerized deployments."],"tags":["filesystem","file-not-found","key-management"],"backgroundTag":"file-open-failed","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"}