plandex-ai/plandex · error

error marshalling result: %v

Error message

error marshalling result: %v

What it means

StorePlanResult persists a plan result by marshalling it to indented JSON before writing to the plan results directory. If json.MarshalIndent fails — which should be nearly impossible for plain result structs but can happen with unsupported types (channels, funcs, cyclic references, custom MarshalJSON errors) — the error is wrapped with this message and nothing is written.

Source

Thrown at app/server/db/result_helpers.go:33

	"time"

	shared "plandex-shared"

	"github.com/google/uuid"
)

func StorePlanResult(result *PlanFileResult) error {
	now := time.Now()
	if result.Id == "" {
		result.Id = uuid.New().String()
		result.CreatedAt = now
	}
	result.UpdatedAt = now

	bytes, err := json.MarshalIndent(result, "", "  ")

	if err != nil {
		return fmt.Errorf("error marshalling result: %v", err)
	}

	resultsDir := getPlanResultsDir(result.OrgId, result.PlanId)

	err = os.MkdirAll(resultsDir, 0755)

	if err != nil {
		return fmt.Errorf("error creating results dir: %v", err)
	}

	log.Printf("Storing plan result: %s - %s", result.Path, result.Id)

	err = os.WriteFile(filepath.Join(resultsDir, result.Id+".json"), bytes, 0644)

	if err != nil {
		return fmt.Errorf("error writing result file: %v", err)
	}

View on GitHub (pinned to e2d772072e)

Solutions

  1. Find the offending field: temporarily marshal with json.Marshal and inspect the wrapped error's field path
  2. Remove or convert unsupported field types (chan, func, complex) to encodable representations
  3. Add json:"-" tags to internal/runtime-only fields that shouldn't be serialized
  4. Register a custom Marshaler or pre-sanitize nested payloads before StorePlanResult

Example fix

// before
type PlanResult struct {
	Callbacks map[int]func() `json:"callbacks"` // unencodable
	UpdatedAt time.Time
}
// after
type PlanResult struct {
	Callbacks map[int]func() `json:"-"` // excluded from JSON
	UpdatedAt time.Time
}
Defensive patterns

Strategy: validation

Validate before calling

// pre-validate the payload encodes before calling StorePlanResult
if _, err := json.Marshal(result); err != nil {
	return fmt.Errorf("plan result not JSON-encodable: %w", err)
}
err := StorePlanResult(result)

Type guard

func jsonEncodable(v any) bool {
	var ok bool
	func() {
		defer func() { if recover() != nil { ok = false } }()
		_, err := json.Marshal(v)
		ok = err == nil
	}()
	return ok
}

Try / catch

err := StorePlanResult(result)
if err != nil {
	if strings.Contains(err.Error(), "error marshalling result") {
		log.Printf("unsupported field in PlanResult: %v", err)
		// fall back to a sanitized copy
		return StorePlanResult(sanitizeForJSON(result))
	}
	return err
}

Prevention

When it happens

Trigger: The result struct (or nested fields) contains values JSON cannot encode, or a field's custom MarshalJSON method returns an error; result.UpdatedAt was just set so the failure comes from other fields.

Common situations: Adding a field of type chan/func/complex to the Result struct; embedding a map with non-string keys (pre-Go1.7 style) or a value that fails marshalling; injecting metrics objects holding unencodable runtime values.

Related errors


AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05). Data as JSON: /api/errors/9ae9928e6df9fff9. Report an issue: GitHub.