sipeed/picoclaw · error
Failed to encode response
Error message
Failed to encode response
What it means
HTTP 500 from GET /api/channels/{name}/config: json.NewEncoder(w).Encode(resp) failed while streaming the already-built response. By this point the response struct was constructed successfully, so an encoding failure almost always means the client went away mid-write (connection reset, navigation, proxy timeout). A marshaling failure is only possible if a code change introduced a non-JSON-serializable field into the response.
Source
Thrown at web/backend/api/channels.go:81
func (h *Handler) handleGetChannelConfig(w http.ResponseWriter, r *http.Request) {
channelName := r.PathValue("name")
item, ok := findChannelCatalogItem(channelName)
if !ok {
http.Error(w, "Channel not found", http.StatusNotFound)
return
}
cfg, err := config.LoadConfig(h.configPath)
if err != nil {
http.Error(w, "Failed to load config", http.StatusInternalServerError)
return
}
resp := buildChannelConfigResponse(cfg, item)
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(resp); err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
}
}
func findChannelCatalogItem(name string) (channelCatalogItem, bool) {
for _, item := range channelCatalog {
if item.Name == name {
return item, true
}
}
return channelCatalogItem{}, false
}
var channelSecretFieldMap = map[string][]string{
"weixin": {"token"},
"telegram": {"token"},
"discord": {"token"},
"slack": {"bot_token", "app_token"},
"feishu": {"app_secret", "encrypt_key", "verification_token"},View on GitHub (pinned to 49183d7e8d)
Solutions
- Correlate the timestamp with client/proxy logs — if the client aborted, it is benign noise
- Check proxy access logs for upstream resets/timeouts and raise idle timeouts if needed
- If reproducible with a stable client, inspect buildChannelConfigResponse output for non-marshalable types
- Consider marshal-then-write so transport and encoding failures are distinguishable
Defensive patterns
Strategy: try-catch
Validate before calling
// server-side hardening: marshal first so encode errors are distinguishable from transport errors
buf, err := json.Marshal(resp)
if err != nil {
http.Error(w, "Failed to encode response", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(buf) Try / catch
Check the Encode error but classify it: after marshaling a plain struct, a write failure is a client disconnect — log at debug and move on; only a true marshal error (fixable struct) warrants a 500. Client-side, one cheap retry usually succeeds.
Prevention
- Marshal-then-write so transport and encoding failures are distinguishable
- Do not abort fetches whose results are still needed, or explicitly ignore abort errors
- Keep response structs limited to JSON-serializable fields and smoke-test them
When it happens
Trigger: Client cancels the fetch (AbortController, tab close) exactly as the response streams; an intermediary (proxy/ALB) times out or resets the upstream connection; a change to buildChannelConfigResponse added a value encoding/json cannot marshal.
Common situations: Frontends aborting in-flight config fetches during rapid navigation; aggressive proxy idle timeouts; response struct gaining chan/func fields after a refactor.
Related errors
- Failed to save config
- model_name is required
- Invalid JSON
- Failed to load config
- Request failed with status ${res.status}
AI-assisted analysis of sipeed/picoclaw@49183d7e8d (2026-08-15).
Data as JSON: /api/errors/bf8d000828b7b7fc.
Report an issue: GitHub.