{"record":{"id":"d852d6b0a4de1798","repo":"plandex-ai/plandex","slug":"error-marshalling-plan-settings-v","errorCode":null,"errorMessage":"error marshalling plan settings: %v","messagePattern":"error marshalling plan settings: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/shared/plan_model_settings.go","lineNumber":241,"sourceCode":"\nfunc (ps *PlanSettings) Equals(other *PlanSettings) bool {\n\treturn ps.GetModelPack().Equals(other.GetModelPack())\n}\n\nfunc (ps PlanSettings) ForCompare() PlanSettings {\n\tps.UpdatedAt = time.Time{}\n\tps.CustomModelPacks = nil\n\tps.CustomModels = nil\n\tps.CustomProviders = nil\n\tps.IsCloud = false\n\tps.Configured = false\n\treturn ps\n}\n\nfunc (ps PlanSettings) DeepCopy() (*PlanSettings, error) {\n\tbytes, err := json.Marshal(ps)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error marshalling plan settings: %v\", err)\n\t}\n\tvar copy PlanSettings\n\terr = json.Unmarshal(bytes, &copy)\n\tif err != nil {\n\t\treturn nil, fmt.Errorf(\"error unmarshalling plan settings: %v\", err)\n\t}\n\treturn &copy, nil\n}\n\nfunc getOptionalModelProviderOptions(settings *PlanSettings, cfg *ModelRoleConfig) ModelProviderOptions {\n\tif cfg == nil {\n\t\treturn ModelProviderOptions{}\n\t}\n\treturn cfg.GetModelProviderOptions(settings)\n}\n","sourceCodeStart":223,"sourceCodeEnd":257,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/shared/plan_model_settings.go#L223-L257","documentation":"PlanSettings.DeepCopy serializes PlanSettings to JSON and back to produce a deep copy. This error wraps a failure in the json.Marshal step, meaning PlanSettings contains a value Go's encoding/json cannot serialize (e.g. an unsupported type like chan/func, a cyclic pointer, or a custom MarshalJSON returning an error).","triggerScenarios":"Calling updateModelSettings or ApplyModelSettings (or any caller of DeepCopy) when the PlanSettings struct has been populated with unmarshalable field values (chan, func, complex, or a field whose MarshalJSON errors).","commonSituations":"A developer added a new field to PlanSettings with an unsupported type, or a nested struct's custom MarshalJSON fails on transiently invalid data; also seen when plugin/extension code stores arbitrary objects in settings.","solutions":["Inspect the wrapped %v error to find the offending field/value reported by encoding/json","Fix or remove the unmarshalable field (chan/func/cyclic pointer) in PlanSettings or give it a `json:\"-\"` tag","Implement or fix the custom MarshalJSON method on the failing type","Add a unit test that round-trips a fully populated PlanSettings through DeepCopy"],"exampleFix":"// before\nTimeout chan time.Time `json:\"timeout\"`\n// after\nTimeout chan time.Time `json:\"-\"`","handlingStrategy":"validation","validationCode":"func validateMarshalable(ps shared.PlanSettings) error {\n    _, err := json.Marshal(ps)\n    return err\n}\n// call validateMarshalable(ps) before updateModelSettings/ApplyModelSettings","typeGuard":null,"tryCatchPattern":"copy, err := ps.DeepCopy()\nif err != nil {\n    if strings.Contains(err.Error(), \"marshalling\") {\n        // log and reject settings change; keep previous settings\n        return fmt.Errorf(\"settings not serializable: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep PlanSettings fields JSON-serializable types only; tag internal fields `json:\"-\"`","Add a round-trip DeepCopy unit test for fully populated settings","Avoid custom MarshalJSON that can fail on partially initialized structs"],"tags":["go","json","serialization","deep-copy"],"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"}