plandex-ai/plandex · error

Error marshalling plan convo:

Error message

Error marshalling plan convo: 

What it means

ListConvoHandler returns this 500 when json.Marshal fails to serialize the []*shared.ConvoMessage slice after the convo was fetched successfully. Like any Marshal failure this points to unsupported field types or a failing custom MarshalJSON, which should not occur with normal ConvoMessage data — it usually means a schema/code change introduced something unserializable.

Source

Thrown at app/server/handlers/plans_convo.go:72

		return nil
	})

	if err != nil {
		log.Println("Error getting plan convo: ", err)
		http.Error(w, "Error getting plan convo: "+err.Error(), http.StatusInternalServerError)
		return
	}

	apiConvoMessages := make([]*shared.ConvoMessage, len(convoMessages))
	for i, convoMessage := range convoMessages {
		apiConvoMessages[i] = convoMessage.ToApi()
	}

	bytes, err := json.Marshal(apiConvoMessages)

	if err != nil {
		log.Println("Error marshalling plan convo: ", err)
		http.Error(w, "Error marshalling plan convo: "+err.Error(), http.StatusInternalServerError)
		return
	}

	log.Println("Successfully processed request for ListConvoHandler")
	w.Write(bytes)

}

func GetPlanStatusHandler(w http.ResponseWriter, r *http.Request) {
	log.Println("Received a request for GetPlanStatusHandler")

	auth := Authenticate(w, r, true)
	if auth == nil {
		return
	}

	vars := mux.Vars(r)
	planId := vars["planId"]

View on GitHub (pinned to e2d772072e)

Solutions

  1. Check the server log for the marshal error detail
  2. Inspect shared.ConvoMessage and ToApi() for newly added unsupported field types
  3. Add a regression test marshalling a real ConvoMessage
  4. If a field is problematic, mark it json:"-" or convert it to a serializable representation

Example fix

// before
CreatedAt customTime // type with failing MarshalJSON
// after
CreatedAt time.Time `json:"createdAt"` // use standard time.Time
Defensive patterns

Strategy: try-catch

Type guard

function isConvoMessageSerializable(m) {
  return typeof m === 'object' && m !== null
    && typeof m.id === 'string'
    && (typeof m.text === 'string' || m.text == null);
}

Try / catch

try {
  const convo = await listPlanConvo(planId, branch);
} catch (e) {
  if (/Error marshalling plan convo/.test(e.message)) {
    log.error('Server-side serialization defect in ConvoMessage — report to maintainers');
  }
  throw e;
}

Prevention

When it happens

Trigger: json.Marshal(apiConvoMessages) errors — only realistic if ConvoMessage or its ToApi() output gains an unsupported type (channel, func, cyclic reference) or a field's MarshalJSON returns an error.

Common situations: Recent change to shared.ConvoMessage added a non-serializable field or a custom marshaller that errors; corrupted data feeding a cyclic pointer.

Related errors


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