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

  1. Only call Chat() from within a GoFrame HTTP handler where gctx/ghttp context is available
  2. Propagate the original request context into goroutines (go func(ctx){...}(o.Ctx)) instead of context.Background()
  3. Set o.Ctx from the handler's request context before calling Chat
  4. 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

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


AI-assisted analysis of Billionmail/BillionMail@fc36c76c05 (2026-09-05). Data as JSON: /api/errors/a4b2439c0628a3e3. Report an issue: GitHub.