{"record":{"id":"442c90df002adccf","repo":"henrygd/beszel","slug":"failed-to-marshal-request-w","errorCode":null,"errorMessage":"failed to marshal request: %w","messagePattern":"failed to marshal request: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/hub/ws/request_manager.go","lineNumber":96,"sourceCode":"\t\trm.cancelRequest(reqID)\n\t\treturn nil, fmt.Errorf(\"failed to send request: %w\", err)\n\t}\n\n\t// Start cleanup watcher for timeout/cancellation\n\tgo rm.cleanupRequest(req)\n\n\treturn req, nil\n}\n\n// sendMessage encodes and sends a message over WebSocket\nfunc (rm *RequestManager) sendMessage(data any) error {\n\tif rm.conn == nil {\n\t\treturn gws.ErrConnClosed\n\t}\n\n\tbytes, err := cbor.Marshal(data)\n\tif err != nil {\n\t\treturn fmt.Errorf(\"failed to marshal request: %w\", err)\n\t}\n\n\treturn rm.conn.WriteMessage(gws.OpcodeBinary, bytes)\n}\n\n// handleResponse processes a single response message\nfunc (rm *RequestManager) handleResponse(message *gws.Message) {\n\tvar response common.AgentResponse\n\tif err := cbor.Unmarshal(message.Data.Bytes(), &response); err != nil {\n\t\t// Legacy response without ID - route to first pending request of any type\n\t\trm.routeLegacyResponse(message)\n\t\treturn\n\t}\n\n\tif response.Id == nil {\n\t\trm.routeLegacyResponse(message)\n\t\treturn\n\t}","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/henrygd/beszel/blob/b38fb7dafa60812cc22e6a84ce313e94f1ce0a32/internal/hub/ws/request_manager.go#L78-L114","documentation":"sendMessage CBOR-marshals the request payload before writing it to the WebSocket. This error is returned when cbor.Marshal fails on the request data, so nothing is sent over the wire.","triggerScenarios":"Passing a request payload containing types cbor.Marshal cannot encode (e.g. channels, funcs, cyclic structures, or unexported fields expected to serialize) to SendRequest.","commonSituations":"Sending custom structs with unsupported field types or channels; attaching context values or non-serializable objects to the request; a custom CBOR encoder mode rejecting a type.","solutions":["Log the wrapped cause (%w) to identify the offending value","Ensure the request payload contains only CBOR-serializable types (primitives, slices, maps, structs with exported fields)","Send nil or a plain struct/map as the request data"],"exampleFix":"// before\nreq := map[string]any{\"cb\": make(chan int)} // not CBOR-serializable\nrm.SendRequest(ctx, action, req)\n// after\nreq := map[string]any{\"action\": \"status\"}\nrm.SendRequest(ctx, action, req)","handlingStrategy":"validation","validationCode":"if err := cbor.Marshal(data); err != nil {\n    return fmt.Errorf(\"request payload not CBOR-serializable: %w\", err)\n}","typeGuard":null,"tryCatchPattern":"if _, err := rm.SendRequest(ctx, action, data); err != nil {\n    if strings.Contains(err.Error(), \"failed to marshal request\") { /* fix payload types */ }\n    return err\n}","preventionTips":["Send only CBOR-serializable payloads (primitives, maps, slices, exported struct fields)","Avoid channels, funcs, and cyclic references in request data","Pre-send smoke-test new payload types with cbor.Marshal in tests"],"tags":["cbor","serialization","websocket"],"backgroundTag":"request-marshaling-failed","analyzedSha":"b38fb7dafa60812cc22e6a84ce313e94f1ce0a32","analyzedAt":"2026-08-31T15:10:10.149Z","schemaVersion":2},"datasetVersion":"2026-08-31T22:30:34.772Z"}