plandex-ai/plandex · error

error unmarshalling JSON file: %v

Error message

error unmarshalling JSON file: %v

What it means

After reading the local custom-models JSON, CustomModelsCheckLocalChanges unmarshals it into shared.ClientModelsInput; a parse failure is wrapped as 'error unmarshalling JSON file: %v'. This means the file exists and is readable but its content is not valid JSON of the expected shape.

Source

Thrown at app/cli/lib/custom_models.go:113

	exists, err := fs.FileExists(path)
	if err != nil {
		return CustomModelsCheckLocalChangesResult{}, err
	}

	if !exists {
		return CustomModelsCheckLocalChangesResult{}, nil
	}

	localJsonData, err := os.ReadFile(path)
	if err != nil {
		return CustomModelsCheckLocalChangesResult{}, fmt.Errorf("error reading JSON file: %v", err)
	}

	var localClientModelsInput shared.ClientModelsInput
	err = json.Unmarshal(localJsonData, &localClientModelsInput)
	if err != nil {
		return CustomModelsCheckLocalChangesResult{}, fmt.Errorf("error unmarshalling JSON file: %v", err)
	}

	localModelsInput := localClientModelsInput.ToModelsInput()

	lastSavedHash, err := os.ReadFile(hashPath)

	if err != nil && !os.IsNotExist(err) {
		return CustomModelsCheckLocalChangesResult{}, fmt.Errorf("error reading hash file: %v", err)
	}

	currentHash, err := localModelsInput.Hash()
	if err != nil {
		return CustomModelsCheckLocalChangesResult{}, fmt.Errorf("error hashing models: %v", err)
	}

	return CustomModelsCheckLocalChangesResult{
		HasLocalChanges:  currentHash != string(lastSavedHash),
		LocalModelsInput: localModelsInput,

View on GitHub (pinned to e2d772072e)

Solutions

  1. Validate the JSON with a linter/parser and fix syntax errors
  2. Delete or rename the file and rerun the custom-models sync to regenerate it
  3. If it appeared after an upgrade, let the sync rewrite the file in the new schema
  4. Compare the file against the expected ClientModelsInput structure for type mismatches

Example fix

// before: hard failure on malformed cache file
err = json.Unmarshal(localJsonData, &localClientModelsInput)
if err != nil {
    return CustomModelsCheckLocalChangesResult{}, fmt.Errorf("error unmarshalling JSON file: %v", err)
}
// after: caller resets corrupted cache
if json.Valid(localJsonData) == false {
    os.Remove(path) // force resync
}
Defensive patterns

Strategy: validation

Validate before calling

data, err := os.ReadFile(path)
if err == nil && !json.Valid(data) {
    os.Remove(path) // corrupted cache; force regeneration
}

Type guard

func validClientModelsInput(data []byte) bool {
    var in shared.ClientModelsInput
    return json.Unmarshal(data, &in) == nil
}

Try / catch

res, err := CustomModelsCheckLocalChanges(...)
if err != nil && strings.Contains(err.Error(), "error unmarshalling JSON file") {
    os.Rename(path, path+".bak") // preserve for inspection, then resync
    return SyncCustomModels()
}

Prevention

When it happens

Trigger: json.Unmarshal(localJsonData, &localClientModelsInput) fails — truncated write, manual edit introduced invalid JSON, schema drift (fields changed type/shape across app versions), or empty/corrupted file.

Common situations: User hand-edited custom-models.json and broke the syntax; crash/interrupt during a previous write left a truncated file; upgrading the CLI changed the ClientModelsInput schema so old files no longer decode.

Understand the failure class

Background: "failed to unmarshal" / json.Unmarshal errors: why parsing a response into a Go struct fails and how to fix it — this error's family across 23 libraries.

Related errors


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