{"record":{"id":"56c1baeebedbaef2","repo":"plandex-ai/plandex","slug":"error-marshalling-users-err-error","errorCode":null,"errorMessage":"Error marshalling users: {err.Error()}","messagePattern":"Error marshalling users: (.+?)","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"app/server/handlers/users.go","lineNumber":84,"sourceCode":"\t\thttp.Error(w, \"Error listing org users: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\torgUsersByUserId := make(map[string]*shared.OrgUser)\n\tfor _, orgUser := range orgUsers {\n\t\torgUsersByUserId[orgUser.UserId] = orgUser.ToApi()\n\t}\n\n\tresp := shared.ListUsersResponse{\n\t\tUsers:            apiUsers,\n\t\tOrgUsersByUserId: orgUsersByUserId,\n\t}\n\n\tbytes, err := json.Marshal(resp)\n\n\tif err != nil {\n\t\tlog.Println(\"Error marshalling users: \", err)\n\t\thttp.Error(w, \"Error marshalling users: \"+err.Error(), http.StatusInternalServerError)\n\t\treturn\n\t}\n\n\tlog.Println(\"Successfully processed request for ListUsersHandler\")\n\n\tw.Write(bytes)\n}\n\nfunc DeleteOrgUserHandler(w http.ResponseWriter, r *http.Request) {\n\tlog.Println(\"Received a request for DeleteOrgUserHandler\")\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 user management\",\n\t\t})\n\t\treturn","sourceCodeStart":66,"sourceCodeEnd":102,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/users.go#L66-L102","documentation":"ListUsersHandler failed to serialize the ListUsersResponse (Users plus OrgUsersByUserId map) with encoding/json before writing the HTTP response. json.Marshal only errors on unsupported types (channels, funcs, cycles), so this almost always indicates a data-model defect, not a user mistake. The client receives the raw json error string appended to this message with HTTP 500.","triggerScenarios":"json.Marshal(resp) returns an error — e.g. a field on a User/ToApi() struct contains a channel, func, or a reference cycle, or a custom MarshalJSON method panics/returns an error.","commonSituations":"Someone adds a field of type func, chan, or a cyclic pointer (e.g. *User pointing back to *Org) to the shared API structs; a custom Marshaler on ToApi() output returns an error on empty/edge-case data.","solutions":["Inspect the server log line 'Error marshalling users: ' for the exact json.UnsupportedTypeError / UnsupportedValueError and field path","Remove or wrap unsupported field types (chan, func, complex) on shared.ListUsersResponse and the structs produced by ToApi()","Break reference cycles in the response structs by copying values instead of pointers back to parent objects","Add a unit test that marshals a fully populated ListUsersResponse fixture"],"exampleFix":"// before\ntype User struct {\n    Callback func()\n}\n// after\ntype User struct {\n    CallbackName string\n}","handlingStrategy":"validation","validationCode":"if err := json.NewEncoder(io.Discard).Encode(resp); err != nil {\n    return fmt.Errorf(\"response not serializable: %w\", err)\n}","typeGuard":"func isMarshalable(v any) bool {\n    return json.NewEncoder(io.Discard).Encode(v) == nil\n}","tryCatchPattern":"bytes, err := json.Marshal(resp)\nif err != nil {\n    var ute *json.UnsupportedTypeError\n    if errors.As(err, &ute) {\n        log.Printf(\"unsupported type at field %s\", ute.Type)\n    }\n    http.Error(w, \"internal error\", http.StatusInternalServerError)\n    return\n}","preventionTips":["Keep API response structs limited to JSON-native types (string, number, bool, slice, map, nested structs)","Add a marshalling smoke test for every response type in CI","Never expose func/chan fields via ToApi() converters","Use json.NewEncoder against io.Discard as a cheap pre-flight check in dev builds"],"tags":["go","json","serialization","http-handler"],"backgroundTag":"json-marshalling-failed","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}