plandex-ai/plandex · error
error marshalling plan apply: %v
Error message
error marshalling plan apply: %v
What it means
After all apply goroutines succeed, ApplyPlan builds a PlanApply record and serializes it with json.MarshalIndent before writing it to the plan's applies directory. If marshalling fails, "error marshalling plan apply: %v" is returned. In practice this is rare — PlanApply is a plain struct of strings, UUIDs, and timestamps — and almost always indicates an impossible-to-marshal field was added to the struct (e.g., a channel, func, or unsupported custom type) rather than bad caller input.
Source
Thrown at app/server/db/result_helpers.go:746
var descriptionIds []string
var messageIds []string
for _, result := range pendingDbResults {
resultIds = append(resultIds, result.Id)
}
for _, desc := range convoMessageDescriptions {
descriptionIds = append(descriptionIds, desc.Id)
messageIds = append(messageIds, desc.ConvoMessageId)
}
planApply.PlanFileResultIds = resultIds
planApply.ConvoMessageDescriptionIds = descriptionIds
planApply.ConvoMessageIds = messageIds
// Store the PlanApply object
bytes, err := json.MarshalIndent(planApply, "", " ")
if err != nil {
return fmt.Errorf("error marshalling plan apply: %v", err)
}
appliesDir := getPlanAppliesDir(orgId, planId)
err = os.MkdirAll(appliesDir, 0755)
if err != nil {
return fmt.Errorf("error creating applies dir: %v", err)
}
err = os.WriteFile(filepath.Join(appliesDir, planApply.Id+".json"), bytes, 0644)
if err != nil {
return fmt.Errorf("error writing plan apply file: %v", err)
}
msg := "✅ Marked pending results as applied"
currentFiles := currentPlanState.CurrentPlanFiles.Files
var sortedFiles []string
for path := range currentFiles {View on GitHub (pinned to e2d772072e)
Solutions
- Inspect the wrapped json error to identify the offending field type in the PlanApply struct.
- Fix the struct: remove or replace the non-serializable field (channels, funcs, cycles) with a serializable representation.
- If a custom MarshalJSON on PlanApply or a nested type is failing, correct or remove it.
- Note the apply side-effects may already be persisted (results, descriptions, contexts) but no PlanApply record exists; after fixing, re-run apply or write the record manually if appropriate.
- Pin/rollback the recent version change that introduced the new field if an immediate hotfix is not possible.
Example fix
// before: non-serializable field added to PlanApply
type PlanApply struct {
Id string
Results map[string]*PlanFileResult
onChange func() // json: cannot marshal func
}
// after: keep serializable data only
type PlanApply struct {
Id string
Results map[string]*PlanFileResult
// callbacks live outside the persisted record
} Defensive patterns
Strategy: try-catch
Validate before calling
// fail fast on struct changes: verify PlanApply marshals before invoking apply
if _, err := json.Marshal(&db.PlanApply{Id: "smoke", OrgId: orgId, PlanId: planId, UserId: userId, CreatedAt: time.Now()}); err != nil {
return fmt.Errorf("PlanApply struct not serializable: %w", err)
} Try / catch
err := db.ApplyPlan(ctx, params)
if err != nil && strings.Contains(err.Error(), "error marshalling plan apply:") {
// code/schema issue: fix PlanApply struct, not caller input
return fmt.Errorf("record serialization bug, apply side-effects may be partial: %w", err)
} Prevention
- Add a CI test that marshals a fully-populated PlanApply to catch non-serializable fields at build time.
- Keep PlanApply limited to JSON-safe types (strings, UUIDs, timestamps, string slices).
- Run go vet / marshalling smoke tests after any struct change.
- If this fires, check whether a recent merge added a field to PlanApply and roll back or fix it.
When it happens
Trigger: Calling ApplyPlan (any params) when the PlanApply struct contains a field json.MarshalIndent cannot encode: an unsupported type added in a code/schema change, a custom MarshalJSON that errors, or cyclic/non-serializable data placed into the record.
Common situations: A recent code change added a new field to PlanApply with a non-serializable type; a custom type's MarshalJSON implementation panics or errors; embedding of an unserializable runtime object into the record after a merge.
Understand the failure class
Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.
Related errors
- error marshalling models: %v
- error hashing model pack: %v
- error marshalling model pack: %v
- error copying settings: %v
- error marshalling current plan settings: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/98cc6a625bb5d239.
Report an issue: GitHub.