{"record":{"id":"15e72bd5f34b0213","repo":"Wei-Shaw/sub2api","slug":"invalid-request-error","errorCode":"invalid_request_error","errorMessage":"request body is required","messagePattern":"request body is required","errorType":"validation","errorClass":null,"httpStatus":400,"severity":"error","filePath":"backend/internal/handler/grok_audio.go","lineNumber":313,"sourceCode":"\t\t\tQuotaPlatform:      quotaPlatform,\n\t\t\tSessionID:          sessionID,\n\t\t\tChannelUsageFields: clientRequestedUsageFields(c, service.ChannelMappingResult{}, model, result.UpstreamModel),\n\t\t}); err != nil {\n\t\t\tlogger.L().With(\n\t\t\t\tzap.String(\"component\", \"handler.openai_gateway.grok_voice\"),\n\t\t\t\tzap.Int64(\"user_id\", apiKey.User.ID),\n\t\t\t\tzap.Int64(\"api_key_id\", apiKey.ID),\n\t\t\t\tzap.Any(\"group_id\", apiKey.GroupID),\n\t\t\t\tzap.String(\"endpoint\", endpoint),\n\t\t\t\tzap.Int64(\"account_id\", account.ID),\n\t\t\t).Error(\"grok_voice.record_usage_failed\", zap.Error(err))\n\t\t}\n\t})\n}\n\nfunc readGrokVoiceGatewayBody(c *gin.Context) ([]byte, error) {\n\tif c == nil || c.Request == nil {\n\t\treturn nil, errors.New(\"request body is required\")\n\t}\n\tif c.Request.Body == nil {\n\t\tif c.Request.Method == http.MethodGet || c.Request.Method == http.MethodDelete {\n\t\t\treturn nil, nil\n\t\t}\n\t\treturn nil, errors.New(\"request body is required\")\n\t}\n\treturn io.ReadAll(c.Request.Body)\n}\n\n// extractGrokTTSInputText pulls the primary spoken text from a TTS JSON body.\nfunc extractGrokTTSInputText(body []byte) string {\n\tif len(body) == 0 {\n\t\treturn \"\"\n\t}\n\tvar payload map[string]any\n\tif err := json.Unmarshal(body, &payload); err != nil {\n\t\treturn \"\"","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/Wei-Shaw/sub2api/blob/073e92d17178a1ccdb0a27017f572f10c9c7ab62/backend/internal/handler/grok_audio.go#L295-L331","documentation":"Thrown by readGrokVoiceGatewayBody when the gin Context or its Request is nil (code=invalid_request_error). This is a defensive guard before any body read; in normal HTTP serving these are never nil, so encountering it means the handler was invoked programmatically or the request context was corrupted.","triggerScenarios":"Internal/test invocation of the Grok voice gateway handler with a nil *gin.Context, or a nil Request inside a constructed Context. Not reachable through a real HTTP request.","commonSituations":"Unit tests calling the handler directly without a request recorder; middleware or wrappers that pass a nil context in error paths.","solutions":["If seen in tests, construct the handler input with gin.CreateTestContext and set c.Request = httptest.NewRequest(...)","Audit custom middleware that wraps or replaces the context to ensure Request is never dropped"],"exampleFix":"// before\nc := gin.CreateTestContext(t)\nh.handleVoice(c) // c.Request == nil\n// after\nc := gin.CreateTestContext(t)\nc.Request = httptest.NewRequest(http.MethodPost, \"/v1/voice\", strings.NewReader(\"{}\"))\nh.handleVoice(c)","handlingStrategy":"type-guard","validationCode":"// Go: never invoke the handler without a request\nif c == nil || c.Request == nil {\n    return errors.New(\"request context is not initialized\")\n}","typeGuard":"// Go\ntype requestCarrier interface{ GetRequest() *http.Request }\nfunc hasRequest(c any) bool {\n    if g, ok := c.(*gin.Context); ok { return g != nil && g.Request != nil }\n    return false\n}","tryCatchPattern":null,"preventionTips":["In tests, always set c.Request via httptest.NewRequest before invoking handlers","Lint middleware that could pass a nil Context in error branches"],"tags":["grok","voice","validation","defensive"],"backgroundTag":null,"analyzedSha":"073e92d17178a1ccdb0a27017f572f10c9c7ab62","analyzedAt":"2026-08-15T14:33:00.750Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}