{"record":{"id":"c94392e29e9f537d","repo":"plandex-ai/plandex","slug":"error-marshalling-invites","errorCode":null,"errorMessage":"Error marshalling invites: ","messagePattern":"Error marshalling invites: ","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/invites.go","lineNumber":212,"sourceCode":"\n\tinvites, err := db.ListPendingInvites(auth.OrgId)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error listing invites: %v\\n\", err)\n\t\thttp.Error(w, \"Error listing invites: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tvar apiInvites []*shared.Invite\n\tfor _, invite := range invites {\n\t\tapiInvites = append(apiInvites, invite.ToApi())\n\t}\n\n\tbytes, err := json.Marshal(apiInvites)\n\n\tif err != nil {\n\t\tlog.Printf(\"Error marshalling invites: %v\\n\", err)\n\t\thttp.Error(w, \"Error marshalling invites: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tw.Write(bytes)\n\tlog.Println(\"Successfully processed request for ListPendingInvitesHandler\")\n}\n\nfunc ListAcceptedInvitesHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received a request for ListAcceptedInvitesHandler\")\n\n\tif os.Getenv(\"GOENV\") == \"development\" && os.Getenv(\"LOCAL_MODE\") == \"1\" {\n\t\twriteApiError(w, shared.ApiError{\n\t\t\tType:   shared.ApiErrorTypeOther,\n\t\t\tStatus: http.StatusForbidden,\n\t\t\tMsg:    \"Local mode is not supported for invites\",\n\t\t})\n\t\treturn\n\t}","sourceCodeStart":194,"sourceCodeEnd":230,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/invites.go#L194-L230","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ntype Invite struct {\n    Callback func() // unsupported by json.Marshal\n}\n// after\ntype Invite struct {\n    CallbackID string `json:\"callbackId\"` // marshalable representation\n}","handlingStrategy":"try-catch","validationCode":"// unit test the invite model for marshalability before shipping:\nfunc TestInviteMarshal(t *testing.T) {\n    inv := &shared.Invite{Id: \"i1\", Email: \"a@b.com\"}\n    if _, err := json.Marshal(inv); err != nil {\n        t.Fatalf(\"Invite not marshalable: %v\", err)\n    }\n}","typeGuard":"func isMarshalError(statusCode int, body string) bool {\n    return statusCode == http.StatusInternalServerError && strings.Contains(body, \"Error marshalling invites\")\n}","tryCatchPattern":"resp, err := client.Get(pendingInvitesUrl)\nbody, _ := io.ReadAll(resp.Body)\nif resp.StatusCode == 500 && strings.Contains(string(body), \"Error marshalling invites\") {\n    return fmt.Errorf(\"server serialization bug — report/upgrade server version: %s\", body)\n}","preventionTips":["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"],"tags":["json","serialization","http-500","go"],"backgroundTag":"json-marshal-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}