plandex-ai/plandex · error
error marshalling plan settings: %v
Error message
error marshalling plan settings: %v
What it means
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).
Source
Thrown at app/shared/plan_model_settings.go:241
func (ps *PlanSettings) Equals(other *PlanSettings) bool {
return ps.GetModelPack().Equals(other.GetModelPack())
}
func (ps PlanSettings) ForCompare() PlanSettings {
ps.UpdatedAt = time.Time{}
ps.CustomModelPacks = nil
ps.CustomModels = nil
ps.CustomProviders = nil
ps.IsCloud = false
ps.Configured = false
return ps
}
func (ps PlanSettings) DeepCopy() (*PlanSettings, error) {
bytes, err := json.Marshal(ps)
if err != nil {
return nil, fmt.Errorf("error marshalling plan settings: %v", err)
}
var copy PlanSettings
err = json.Unmarshal(bytes, ©)
if err != nil {
return nil, fmt.Errorf("error unmarshalling plan settings: %v", err)
}
return ©, nil
}
func getOptionalModelProviderOptions(settings *PlanSettings, cfg *ModelRoleConfig) ModelProviderOptions {
if cfg == nil {
return ModelProviderOptions{}
}
return cfg.GetModelProviderOptions(settings)
}
View on GitHub (pinned to e2d772072e)
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
Example fix
// before Timeout chan time.Time `json:"timeout"` // after Timeout chan time.Time `json:"-"`
Defensive patterns
Strategy: validation
Validate before calling
func validateMarshalable(ps shared.PlanSettings) error {
_, err := json.Marshal(ps)
return err
}
// call validateMarshalable(ps) before updateModelSettings/ApplyModelSettings Try / catch
copy, err := ps.DeepCopy()
if err != nil {
if strings.Contains(err.Error(), "marshalling") {
// log and reject settings change; keep previous settings
return fmt.Errorf("settings not serializable: %w", err)
}
return err
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Related errors
- error unmarshalling plan settings: %v
- error marshalling models: %v
- error marshalling model pack: %v
- error marshalling current plan settings: %v
- error marshalling convo message: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/d852d6b0a4de1798.
Report an issue: GitHub.