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

  1. 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).
  2. Verify the exact path <exeDir>/etc/ztdo/data-key-<doId>.json and the doId spelling before deleting.
  3. Grant the process user write permission on etc/ztdo if the error is 'permission denied'.
  4. 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

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


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)