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

  1. Inspect the wrapped error: json.Marshal names the offending field/type
  2. Check recently added fields in shared.Invite and its nested types for unsupported types or cycles
  3. Add json tags and ensure all fields are marshalable (use pointers/omit-empty appropriately)
  4. 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

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


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