plandex-ai/plandex · error
error saving hash file: %v
Error message
error saving hash file: %v
What it means
After writing custom-models.json, WriteCustomModelsFile calls SaveCustomModelsHash to persist a hash of the models input alongside it. This error means SaveCustomModelsHash returned an error — either hashing the models input failed or writing the <path>.hash file failed — so the models file exists but its hash cache is missing or stale.
Source
Thrown at app/cli/lib/custom_models.go:156
return fmt.Errorf("error creating directory: %v", err)
}
clientModelsInput := modelsInput.ToClientModelsInput()
clientModelsInput.PrepareUpdate()
jsonData, err := json.MarshalIndent(clientModelsInput, "", " ")
if err != nil {
return fmt.Errorf("error marshalling models: %v", err)
}
err = os.WriteFile(path, jsonData, 0644)
if err != nil {
return fmt.Errorf("error writing file: %v", err)
}
err = SaveCustomModelsHash(path, modelsInput)
if err != nil {
return fmt.Errorf("error saving hash file: %v", err)
}
return nil
}
func SaveCustomModelsHash(basePath string, modelsInput *shared.ModelsInput) error {
hashPath := basePath + ".hash"
hash, err := modelsInput.Hash()
if err != nil {
return fmt.Errorf("error hashing models: %v", err)
}
err = os.WriteFile(hashPath, []byte(hash), 0644)
if err != nil {
return fmt.Errorf("error writing hash file: %v", err)
}
View on GitHub (pinned to e2d772072e)
Solutions
- Inspect the wrapped %v error to distinguish hashing failure from hash-file write failure.
- Fix underlying filesystem issues (permissions, disk space) on ~/.plandex/accounts/<userId>/.
- Delete the stale custom-models.json.hash and re-run the models command so the hash is regenerated.
- Re-sync custom models (plandex models / SyncCustomModels) to rewrite both file and hash consistently.
Example fix
// before rm ~/.plandex/accounts/<userId>/custom-models.json.hash # stale hash // after plandex models # rewrites custom-models.json and regenerates the .hash file
Defensive patterns
Strategy: try-catch
Validate before calling
// Pre-check that the models file and hash directory are writable
info, err := os.Stat(hashPath)
_ = info
if err != nil && !os.IsNotExist(err) {
// handle: hash path inaccessible
} Type guard
func isHashSaveError(err error) bool {
return err != nil && strings.Contains(err.Error(), "error saving hash file")
} Try / catch
if err := lib.WriteCustomModelsFile(path, input); err != nil {
if isHashSaveError(err) {
os.Remove(path + ".hash") // clear stale hash
term.Error("Models written but hash missing; re-run sync")
return
}
return err
} Prevention
- Treat custom-models.json and its .hash as an atomic pair; regenerate both together.
- Delete the .hash file whenever the JSON file is manually edited or restored.
- Keep the accounts directory free of root-owned files.
- Check disk/permission health before bulk model updates.
When it happens
Trigger: modelsInput.Hash() failing, or os.WriteFile(hashPath, ...) failing due to the same directory permission/disk issues as the JSON write (custom_models.go:163-172).
Common situations: Disk full or read-only home dir striking between the two writes; a Hash() implementation failure from a schema version mismatch; hash file locked or owned by another user after sudo usage.
Understand the failure class
Background: "Permission denied" / "Failed to write" file errors: why a library can't write its files to disk (EACCES, EPERM, ENOSPC) and how to fix them — this error's family across 43 libraries.
Related errors
- error reading hash file: %v
- error writing file: %v
- error writing hash file: %v
- error saving model pack roles hash: %v
- error writing hash file: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/8894979ded5307ae.
Report an issue: GitHub.