plandex-ai/plandex · error

error marshalling models: %v

Error message

error marshalling models: %v

What it means

WriteCustomModelsFile marshals the prepared client-side models input to indented JSON before writing custom-models.json. This error means json.MarshalIndent failed on the shared.ModelsInput value, which for a fully-formed struct normally indicates an unsupported value (e.g. a channel, func, or cyclic reference) slipped into the payload. It is a pre-write sanity failure: the file is not touched.

Source

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

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

func WriteCustomModelsFile(path string, modelsInput *shared.ModelsInput) error {
	err := os.MkdirAll(filepath.Dir(path), 0755)
	if err != nil {
		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"

View on GitHub (pinned to e2d772072e)

Solutions

  1. Read the wrapped %v error to identify the offending field/type reported by encoding/json.
  2. Check for a plandex-cli / plandex-shared version mismatch and upgrade both to matching versions.
  3. If you customized ModelsInput or ToClientModelsInput/PrepareUpdate, remove or make JSON-serializable any unsupported field types.
  4. Retry the custom models operation after fixing; the file was not written so no cleanup is needed.

Example fix

// before (custom field added to ModelsInput)
type ModelsInput struct {
  Callback func() // not JSON-marshalable
}
// after
 type ModelsInput struct {
  CallbackName string // marshalable representation
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Go has no pre-marshal validation; guard the call and inspect the wrapped error
if err := lib.WriteCustomModelsFile(path, modelsInput); err != nil {
    if strings.Contains(err.Error(), "error marshalling models") {
        // handle serialization failure: log offending input, skip write
    }
}

Type guard

func isMarshalError(err error) bool {
    return err != nil && strings.Contains(err.Error(), "error marshalling models")
}

Try / catch

if err := lib.WriteCustomModelsFile(path, input); err != nil {
    var wrap *fmt.WrapError // or string-match the sentinel text
    if isMarshalError(err) {
        term.Error("Custom models could not be serialized; file untouched")
        return
    }
    return err
}

Prevention

When it happens

Trigger: Calling WriteCustomModelsFile (via manageCustomModels) when the clientModelsInput struct contains a value the JSON encoder cannot represent — typically a malformed field set programmatically or produced by a schema/ToClientModelsInput bug rather than user input.

Common situations: Custom library modifications adding non-serializable fields to ModelsInput; version mismatch between plandex-cli and plandex-shared where a new field type isn't JSON-marshalable; corrupted in-memory state after a failed update.

Related errors


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