plandex-ai/plandex · error
Error marshalling response
Error message
Error marshalling response
What it means
writeApiError is the shared helper for returning JSON ApiError bodies from HTTP handlers. Before writing the body it marshals the ApiError struct with encoding/json; if that marshal itself fails it logs 'Error marshalling response' and falls back to a plain-text 500 response. This is a defensive last-resort path: an ApiError with non-marshalable field values (e.g. unsupported types like channels, funcs, or invalid numbers such as NaN in custom fields) cannot be serialized.
Source
Thrown at app/server/handlers/err_helper.go:16
package handlers
import (
"encoding/json"
"log"
"net/http"
shared "plandex-shared"
)
func writeApiError(w http.ResponseWriter, apiErr shared.ApiError) {
bytes, err := json.Marshal(apiErr)
if err != nil {
log.Printf("Error marshalling response: %v\n", err)
// If marshalling fails, fall back to a simpler error message
http.Error(w, "Error marshalling response", http.StatusInternalServerError)
return
}
log.Printf("API Error: %v\n", apiErr.Msg)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(apiErr.Status)
_, writeErr := w.Write(bytes)
if writeErr != nil {
log.Printf("Error writing response: %v\n", writeErr)
}
}
View on GitHub (pinned to e2d772072e)
Solutions
- Inspect the log line 'Error marshalling response: %v' to see the json.UnsupportedTypeError and identify the offending field
- Ensure every field of shared.ApiError (and any embedded payload) contains only JSON-serializable types (strings, numbers, bools, slices, maps, structs)
- Convert custom payload values to strings or a typed DTO before constructing the ApiError
- If the ApiError is built from arbitrary data, sanitize it (e.g. re-marshal through json.RawMessage or a generic map[string]interface{}) before passing to writeApiError
Example fix
// before
apiErr := shared.ApiError{Msg: "failed", Details: someChan}
writeApiError(w, apiErr)
// after
apiErr := shared.ApiError{Msg: "failed", Details: fmt.Sprintf("%v", someChan)}
writeApiError(w, apiErr) Defensive patterns
Strategy: fallback
Validate before calling
// Validate the ApiError is JSON-safe before sending
func isJSONSafe(v interface{}) bool {
_, err := json.Marshal(v)
return err == nil
}
if !isJSONSafe(apiErr) {
apiErr = shared.ApiError{Msg: apiErr.Msg} // drop unsafe payload
} Type guard
func safeApiError(e shared.ApiError) shared.ApiError {
b, err := json.Marshal(e)
if err != nil || !json.Valid(b) {
return shared.ApiError{Msg: "internal error"}
}
return e
} Try / catch
// Go has no try/catch; wrap the write and check marshal error at the call site
if b, err := json.Marshal(apiErr); err != nil {
log.Printf("api error not marshalable: %v", err)
http.Error(w, http.StatusText(http.StatusInternalServerError), 500)
return
} Prevention
- Keep ApiError fields limited to JSON-native types
- Never embed channels, funcs, or complex numbers in error payloads
- Unit-test writeApiError with every ApiError variant your handlers produce
- Sanitize dynamic payload data before attaching it to errors
When it happens
Trigger: A handler (CreateAccountHandler, execAuthenticate, InviteUserHandler, ListPendingInvitesHandler, ListAcceptedInvitesHandler, ListAllInvitesHandler) constructs a shared.ApiError whose payload contains a value encoding/json cannot marshal — e.g. a channel, func, complex number, or cyclic data structure placed in an extension/payload field.
Common situations: Developers extending ApiError with a custom Data/Payload field and stuffing runtime objects into it; refactors that change an ID field from string to a struct containing unexported or unsupported types; NaN/Inf floats leaking into error details from computed metrics.
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 response: %v
- Error marshalling response
- error marshalling models: %v
- error marshalling model pack: %v
- error marshalling current plan settings: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/80e6566228cc9591.
Report an issue: GitHub.