{"record":{"id":"9d07b195d952cb38","repo":"plandex-ai/plandex","slug":"error-unmarshalling-plan-settings-v","errorCode":null,"errorMessage":"error unmarshalling plan settings: %v","messagePattern":"error unmarshalling plan settings: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/shared/plan_model_settings.go","lineNumber":246,"sourceCode":"func (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":228,"sourceCodeEnd":257,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/shared/plan_model_settings.go#L228-L257","documentation":"PlanSettings.DeepCopy wraps a failure from json.Unmarshal when decoding the marshalled copy back into a new PlanSettings. This means the marshalled JSON does not conform to PlanSettings' unmarshalling requirements (e.g. a field's UnmarshalJSON rejected the value, or type mismatch).","triggerScenarios":"DeepCopy is invoked via updateModelSettings / ApplyModelSettings and a field's custom UnmarshalJSON returns an error, or a UnmarshalJSON implementation writes into the receiver on invalid input during the marshal→unmarshal round trip.","commonSituations":"Custom UnmarshalJSON methods on PlanSettings fields that validate data and reject recently added or user-supplied values; mismatches introduced by version skew where the settings schema changed.","solutions":["Read the wrapped %v error to identify the failing field path from encoding/json","Fix the custom UnmarshalJSON on the offending field to accept valid states or report clearer errors","Since the bytes came from Marshal of the same struct, verify no field's UnmarshalJSON/MarshalJSON are asymmetric","Round-trip test a fully populated PlanSettings in unit tests"],"exampleFix":"// before\nfunc (t *T) UnmarshalJSON(b []byte) error { ... if bad { return errors.New(\"bad\") } }\n// after\nfunc (t *T) UnmarshalJSON(b []byte) error { ... accept legacy shapes or return nil for empty }","handlingStrategy":"try-catch","validationCode":"func validateRoundTrip(ps shared.PlanSettings) error {\n    copy, err := ps.DeepCopy()\n    if err != nil { return err }\n    if copy == nil { return errors.New(\"nil copy\") }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"copy, err := ps.DeepCopy()\nif err != nil {\n    if strings.Contains(err.Error(), \"unmarshalling\") {\n        return fmt.Errorf(\"settings round-trip failed: %w\", err)\n    }\n    return err\n}","preventionTips":["Keep UnmarshalJSON implementations symmetric with MarshalJSON","Accept legacy/empty payloads in custom UnmarshalJSON","Test DeepCopy after every change to PlanSettings fields"],"tags":["go","json","serialization","deep-copy"],"backgroundTag":"json-unmarshalling-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"}