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
- Read the wrapped %v error to identify the offending field/type reported by encoding/json.
- Check for a plandex-cli / plandex-shared version mismatch and upgrade both to matching versions.
- If you customized ModelsInput or ToClientModelsInput/PrepareUpdate, remove or make JSON-serializable any unsupported field types.
- 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
- Keep ModelsInput fields JSON-serializable (no funcs, channels, or cycles).
- Keep plandex-cli and plandex-shared versions in lockstep.
- Add a unit test that marshals a fully populated ModelsInput fixture.
- Run ToClientModelsInput/PrepareUpdate through tests when changing schemas.
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
- error marshalling model pack: %v
- error marshalling current plan settings: %v
- error marshalling convo message: %v
- error marshalling convo message description: %v
- error marshalling result: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/6bd1b5d37640b94a.
Report an issue: GitHub.