{"record":{"id":"6bd1b5d37640b94a","repo":"plandex-ai/plandex","slug":"error-marshalling-models-v","errorCode":null,"errorMessage":"error marshalling models: %v","messagePattern":"error marshalling models: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/cli/lib/custom_models.go","lineNumber":146,"sourceCode":"\n\treturn CustomModelsCheckLocalChangesResult{\n\t\tHasLocalChanges:  currentHash != string(lastSavedHash),\n\t\tLocalModelsInput: localModelsInput,\n\t}, nil\n}\n\nfunc WriteCustomModelsFile(path string, modelsInput *shared.ModelsInput) error {\n\terr := os.MkdirAll(filepath.Dir(path), 0755)\n\tif err != nil {\n\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","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/cli/lib/custom_models.go#L128-L164","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (custom field added to ModelsInput)\ntype ModelsInput struct {\n  Callback func() // not JSON-marshalable\n}\n// after\n type ModelsInput struct {\n  CallbackName string // marshalable representation\n}","handlingStrategy":"try-catch","validationCode":"// Go has no pre-marshal validation; guard the call and inspect the wrapped error\nif err := lib.WriteCustomModelsFile(path, modelsInput); err != nil {\n    if strings.Contains(err.Error(), \"error marshalling models\") {\n        // handle serialization failure: log offending input, skip write\n    }\n}","typeGuard":"func isMarshalError(err error) bool {\n    return err != nil && strings.Contains(err.Error(), \"error marshalling models\")\n}","tryCatchPattern":"if err := lib.WriteCustomModelsFile(path, input); err != nil {\n    var wrap *fmt.WrapError // or string-match the sentinel text\n    if isMarshalError(err) {\n        term.Error(\"Custom models could not be serialized; file untouched\")\n        return\n    }\n    return err\n}","preventionTips":["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."],"tags":["go","json","serialization","custom-models"],"backgroundTag":"json-marshalling-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}