OpenNHP/opennhp · warning
failed to delete file
Error message
failed to delete file: %v
What it means
DataPrivateKeyStore.Delete removes data-key-<doId>.json from <exeDir>/etc/ztdo via os.Remove. If removal fails - most commonly because the file does not exist, or the directory is not writable - this wrapped error is returned. Note there is no ENOENT special-casing: deleting a key that was never saved also produces this error.
Solutions
- Check the wrapped os error: if it is ENOENT ('no such file or directory'), treat the delete as already done and ignore, or use errors.Is(err, fs.ErrNotExist).
- Verify the exact path <exeDir>/etc/ztdo/data-key-<doId>.json and the doId spelling before deleting.
- Grant the process user write permission on etc/ztdo if the error is 'permission denied'.
- Guard concurrent deletes with a lock or check os.Stat before calling Delete.
Example fix
// before: Delete fails on missing file
if err := store.Delete(doId); err != nil { return err }
// after: tolerate already-deleted keys
if err := store.Delete(doId); err != nil && !errors.Is(err, fs.ErrNotExist) {
return err
} Defensive patterns
Strategy: try-catch
Validate before calling
path := filepath.Join(common.ExeDirPath, "etc/ztdo", "data-key-"+doId+".json")
if _, err := os.Stat(path); os.IsNotExist(err) {
return nil // nothing to delete
} Type guard
func isNotExistWrapped(err error) bool {
return errors.Is(err, fs.ErrNotExist)
} Try / catch
err := store.Delete(doId)
if err != nil && !errors.Is(err, fs.ErrNotExist) {
return fmt.Errorf("deleting data key %s: %w", doId, err)
} Prevention
- Treat ENOENT as success in cleanup/teardown paths to make deletes idempotent.
- Serialize key-file operations with a lock to avoid delete/delete races.
- Confirm the doId before deleting - the filename is derived from it.
- Run cleanup under the same user that created the files to avoid permission surprises.
When it happens
Trigger: Calling Delete(doId) when: (1) no key file exists for that doId (never saved, already deleted, or mistyped doId); (2) the process lacks write permission on etc/ztdo; (3) the file is locked/EBUSY on some platforms or sits on a read-only filesystem.
Common situations: Idempotent teardown scripts calling Delete unconditionally; cleanup path racing with another process that already deleted the key; running as a different user than the one who created the files.
Understand the failure class
Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.
Related errors
- resource not found
- Error: fail to generating temporary file path
- failed to open file
- error reading file
- failed to create etc directory
AI-assisted analysis of OpenNHP/opennhp@6e04ca5ff0 (2026-09-07).
Data as JSON: /api/errors/a8dded4abc90365e.
Report an issue: GitHub.
Appendix: source
Thrown at endpoints/db/utils.go:95
file, err := os.Create(fullPath)
if err != nil {
return fmt.Errorf("failed to create file: %v", err)
}
defer file.Close()
_, err = file.Write(d.toJson())
return err
}
func (d *DataPrivateKeyStore) Delete(doId string) error {
etcDir := "etc/ztdo"
fileName := "data-key-" + doId + ".json"
fullPath := filepath.Join(common.ExeDirPath, etcDir, fileName)
// delete the file
err := os.Remove(fullPath)
if err != nil {
return fmt.Errorf("failed to delete file: %v", err)
}
return nil
}
func (d *DataPrivateKeyStore) toJson() []byte {
dataPrkStoreJson, err := json.Marshal(d)
if err != nil {
return []byte("{}")
} else {
return dataPrkStoreJson
}
}
func (d *DataPrivateKeyStore) fromJson(jsonData []byte) error {
err := json.Unmarshal(jsonData, d)
if err != nil {
return fmt.Errorf("json parsing error: %s", err)
}View on GitHub (pinned to 6e04ca5ff0)