{"record":{"id":"8894979ded5307ae","repo":"plandex-ai/plandex","slug":"error-saving-hash-file-v","errorCode":null,"errorMessage":"error saving hash file: %v","messagePattern":"error saving hash file: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/custom_models.go","lineNumber":156,"sourceCode":"\t\treturn fmt.Errorf(\"error creating directory: %v\", err)\n\t}\n\n\tclientModelsInput := modelsInput.ToClientModelsInput()\n\tclientModelsInput.PrepareUpdate()\n\n\tjsonData, err := json.MarshalIndent(clientModelsInput, \"\", \"  \")\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error marshalling models: %v\", err)\n\t}\n\n\terr = os.WriteFile(path, jsonData, 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing file: %v\", err)\n\t}\n\n\terr = SaveCustomModelsHash(path, modelsInput)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error saving hash file: %v\", err)\n\t}\n\n\treturn nil\n}\n\nfunc SaveCustomModelsHash(basePath string, modelsInput *shared.ModelsInput) error {\n\thashPath := basePath + \".hash\"\n\n\thash, err := modelsInput.Hash()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error hashing models: %v\", err)\n\t}\n\n\terr = os.WriteFile(hashPath, []byte(hash), 0644)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"error writing hash file: %v\", err)\n\t}\n","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/custom_models.go#L138-L174","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nrm ~/.plandex/accounts/<userId>/custom-models.json.hash  # stale hash\n// after\nplandex models  # rewrites custom-models.json and regenerates the .hash file","handlingStrategy":"try-catch","validationCode":"// Pre-check that the models file and hash directory are writable\ninfo, err := os.Stat(hashPath)\n_ = info\nif err != nil && !os.IsNotExist(err) {\n    // handle: hash path inaccessible\n}","typeGuard":"func isHashSaveError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"error saving hash file\")\n}","tryCatchPattern":"if err := lib.WriteCustomModelsFile(path, input); err != nil {\n    if isHashSaveError(err) {\n        os.Remove(path + \".hash\") // clear stale hash\n        term.Error(\"Models written but hash missing; re-run sync\")\n        return\n    }\n    return err\n}","preventionTips":["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."],"tags":["go","filesystem","hash","custom-models"],"backgroundTag":"file-write-permission-denied","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-12T22:17:10.623Z"}