plandex-ai/plandex · error

error writing hash file: %v

Error message

error writing hash file: %v

What it means

SaveModelPackRolesHash writes the computed hash to <basePath>.hash with os.WriteFile (0644). Failures are wrapped as 'error writing hash file: %v'. The settings JSON itself may already exist, so a failure here leaves the pair out of sync and local-change detection may misbehave.

Source

Thrown at app/cli/lib/model_settings.go:111

	err = SaveModelPackRolesHash(path, &modelPackSchemaRoles)
	if err != nil {
		return fmt.Errorf("error saving model pack roles hash: %v", err)
	}

	return nil
}

func SaveModelPackRolesHash(basePath string, serverModelPack *shared.ModelPackSchemaRoles) error {
	hashPath := basePath + ".hash"

	hash, err := serverModelPack.Hash()
	if err != nil {
		return fmt.Errorf("error hashing model pack: %v", err)
	}

	err = os.WriteFile(hashPath, []byte(hash), 0644)
	if err != nil {
		return fmt.Errorf("error writing hash file: %v", err)
	}

	return nil
}

func ApplyModelSettings(path string, originalSettings *shared.PlanSettings) (*shared.PlanSettings, error) {
	jsonData, err := os.ReadFile(path)
	if err != nil {
		return nil, fmt.Errorf("error reading JSON file: %v", err)
	}

	settings, err := originalSettings.DeepCopy()
	if err != nil {
		return nil, fmt.Errorf("error copying settings: %v", err)
	}

	clientModelPackRoles, err := schema.ValidateModelPackInlineJSON(jsonData)
	if err != nil {

View on GitHub (pinned to e2d772072e)

Solutions

  1. Fix permissions on the directory containing the settings file: chmod u+rw on the .hash path and its directory
  2. Check the wrapped OS error; free space/quota if ENOSPC or EDQUOT
  3. Delete the stale .hash file if it is a directory or corrupt, then retry the operation
  4. Exclude ~/.plandex from file-sync tools that can lock or replace files

Example fix

// before
error writing hash file: open ~/.plandex/xyz/model-settings.json.hash: read-only file system
// after
mount -o remount,rw ~/.plandex  # or choose a writable HOME: export HOME=/writable/dir
Defensive patterns

Strategy: validation

Validate before calling

hashPath := path + ".hash"
if info, err := os.Stat(hashPath); err == nil && info.IsDir() {
    return fmt.Errorf("%s is a directory", hashPath)
}
if f, err := os.OpenFile(hashPath, os.O_WRONLY|os.O_CREATE, 0o644); err != nil {
    return err
} else { f.Close() }

Try / catch

if err := lib.SaveModelPackRolesHash(path, &roles); err != nil {
    if strings.Contains(err.Error(), "error writing hash file") {
        // fix permissions/mount on hashPath, then retry
    }
    return err
}

Prevention

When it happens

Trigger: os.WriteFile(hashPath, ...) fails because the .hash file or its directory is read-only/owned by another user, the disk is full, or a directory exists where the .hash file should be.

Common situations: Read-only ~/.plandex mount in CI or containers; concurrent CLI runs racing on the same plan; editors or sync tools (Dropbox) locking files.

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


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/b780f9091107e5a3. Report an issue: GitHub.