Billionmail/BillionMail · error
request context is nil
Error message
request context is nil
What it means
Chat() resolves the HTTP request from the stored context via ghttp.RequestFromCtx(o.Ctx); if o.Ctx carries no GoFrame request (nil), it cannot write streaming events, so it returns this error before doing any work.
Source
Thrown at core/internal/service/askai/openai.go:733
}
// Recursively call the function to handle tool calls
return o.CreateChatCompletionStream(request, req, isText)
}
// Ensure the response is properly closed
o.WriteHtml() // Write HTML content if the chat has ended
o.WriteMessage(o.Content, finishReason) // Write the final message to the chat
o.WriteEvent(request, "", isText, true) // Write final event to indicate completion
return nil
}
func (o *OpenAI) Chat(content string, isText bool) error {
// Implementation for sending a chat message to OpenAI
// This function should handle the logic for sending a chat message and return the response or any error encountered
request := ghttp.RequestFromCtx(o.Ctx)
if request == nil {
return errors.New("request context is nil")
}
if o.Client == nil {
o.GetClient()
}
tools := []openai.Tool{
o.RegisterWebSearchTool(), // Register the web search tool for HTTP requests
}
o.UserContent = content // Set the user content to the provided content
req := openai.ChatCompletionRequest{
Model: o.ModelId,
MaxCompletionTokens: o.MaxTokens,
Messages: o.GetMessages(), // Get the messages for the chat
Temperature: 0.6, // Set temperature for the chat completion
Stream: true,View on GitHub (pinned to fc36c76c05)
Solutions
- Only call Chat() from within a GoFrame HTTP handler where gctx/ghttp context is available
- Propagate the original request context into goroutines (go func(ctx){...}(o.Ctx)) instead of context.Background()
- Set o.Ctx from the handler's request context before calling Chat
- Refactor Chat to accept an event writer abstraction so it can run without an ghttp.Request
Example fix
// before
worker := o
o.Ctx = context.Background() // request lost
go worker.Chat(prompt, true)
// after
// in the HTTP handler:
o.Ctx = r.Context() // ghttp request context
go func(ctx context.Context) { o.Chat(prompt, true) }(o.Ctx) Defensive patterns
Strategy: type-guard
Validate before calling
if ghttp.RequestFromCtx(o.Ctx) == nil {
return errors.New("Chat requires an active ghttp request context")
} Type guard
func hasHttpContext(ctx context.Context) bool {
return ghttp.RequestFromCtx(ctx) != nil
} Try / catch
if err := o.Chat(prompt, isText); err != nil {
if err.Error() == "request context is nil" {
return fmt.Errorf("Chat must be called from a GoFrame HTTP handler: %w", err)
}
return err
} Prevention
- Always assign o.Ctx from the handler's request before calling Chat
- Pass the original context into spawned goroutines, never context.Background()
- Assert request availability in unit tests before exercising Chat
- Avoid running Chat from background workers unless an event-writer abstraction is provided
When it happens
Trigger: Calling OpenAI.Chat() with o.Ctx unset, with a plain context.Background(), or from a background goroutine/worker where the original ghttp request context is not propagated.
Common situations: Invoking Chat from a queue consumer or cron job; spawning a goroutine with a detached context; constructing OpenAI manually in tests without a GoFrame handler context; middleware that replaced the context.
Related errors
- base URL accessibility test failed: %w
- API key validation failed: %w
- unexpected API response: %d %s
- download file failed:
- base URL not configured
AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05).
Data as JSON: /api/errors/a4b2439c0628a3e3.
Report an issue: GitHub.