plandex-ai/plandex · error
Error marshalling invites:
Error message
Error marshalling invites:
What it means
ListPendingInvitesHandler wraps any error from json.Marshal(apiInvites) into an HTTP 500 prefixed with 'Error marshalling invites: '. In practice json.Marshal on []*shared.Invite almost never fails unless a field cannot be serialized (e.g. an unsupported type like a channel, func, or a cyclic pointer graph introduced in the Invite struct). It is a programming/data-model bug, not an operational fault.
Source
Thrown at app/server/handlers/invites.go:212
invites, err := db.ListPendingInvites(auth.OrgId)
if err != nil {
log.Printf("Error listing invites: %v\n", err)
http.Error(w, "Error listing invites: "+err.Error(), http.StatusInternalServerError)
return
}
var apiInvites []*shared.Invite
for _, invite := range invites {
apiInvites = append(apiInvites, invite.ToApi())
}
bytes, err := json.Marshal(apiInvites)
if err != nil {
log.Printf("Error marshalling invites: %v\n", err)
http.Error(w, "Error marshalling invites: "+err.Error(), http.StatusInternalServerError)
return
}
w.Write(bytes)
log.Println("Successfully processed request for ListPendingInvitesHandler")
}
func ListAcceptedInvitesHandler(w http.ResponseWriter, r *http.Request) {
log.Println("Received a request for ListAcceptedInvitesHandler")
if os.Getenv("GOENV") == "development" && os.Getenv("LOCAL_MODE") == "1" {
writeApiError(w, shared.ApiError{
Type: shared.ApiErrorTypeOther,
Status: http.StatusForbidden,
Msg: "Local mode is not supported for invites",
})
return
}View on GitHub (pinned to e2d772072e)
Solutions
- Inspect the wrapped error: json.Marshal names the offending field/type
- Check recently added fields in shared.Invite and its nested types for unsupported types or cycles
- Add json tags and ensure all fields are marshalable (use pointers/omit-empty appropriately)
- Add a unit test marshalling an Invite with representative values
Example fix
// before
type Invite struct {
Callback func() // unsupported by json.Marshal
}
// after
type Invite struct {
CallbackID string `json:"callbackId"` // marshalable representation
} Defensive patterns
Strategy: try-catch
Validate before calling
// unit test the invite model for marshalability before shipping:
func TestInviteMarshal(t *testing.T) {
inv := &shared.Invite{Id: "i1", Email: "a@b.com"}
if _, err := json.Marshal(inv); err != nil {
t.Fatalf("Invite not marshalable: %v", err)
}
} Type guard
func isMarshalError(statusCode int, body string) bool {
return statusCode == http.StatusInternalServerError && strings.Contains(body, "Error marshalling invites")
} Try / catch
resp, err := client.Get(pendingInvitesUrl)
body, _ := io.ReadAll(resp.Body)
if resp.StatusCode == 500 && strings.Contains(string(body), "Error marshalling invites") {
return fmt.Errorf("server serialization bug — report/upgrade server version: %s", body)
} Prevention
- Add CI unit tests that json.Marshal representative Invite values
- Never add chan/func/cyclic fields to shared API structs
- Give every API struct field an explicit json tag
- A custom MarshalJSON must never return an error for valid states
When it happens
Trigger: GET to the pending-invites endpoint where the shared.Invite struct (or a nested field added to it) contains a value json.Marshal cannot encode, or a custom MarshalJSON method returns an error.
Common situations: A developer recently added a field of unsupported type (chan, func, complex) to shared.Invite or its nested types; introducing a reference cycle between structs; a custom marshaller that errors on nil or unexpected states.
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 contexts:
- Error marshalling response:
- Error marshalling plans:
- Error marshalling response:
- Error marshalling projects:
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/c94392e29e9f537d.
Report an issue: GitHub.