Tencent/WeKnora · error
LLM returned nil response
Error message
LLM returned nil response
What it means
callErr with this message is produced inside the wiki ingest LLM retry loop when chatModel.Chat returns no error but a nil response object. Since the code needs response.Content, a nil response is treated as a failed call and becomes lastErr; if not transient, it aborts with "LLM call failed". It usually indicates a model adapter bug or an upstream API returning an empty 200 response.
Source
Thrown at internal/application/service/wiki_ingest.go:2588
execute := func() (interface{}, error) {
releaseWarmup := func() {}
if tenantScoped && promptTpl == agent.WikiPageModifyUserPrompt && strings.TrimSpace(maskedData["SharedSourceContexts"]) != "" {
var warmupErr error
releaseWarmup, warmupErr = s.awaitWikiPromptWarmup(ctx, warmupKey)
if warmupErr != nil {
return "", warmupErr
}
}
defer releaseWarmup()
var lastErr error
for attempt := 1; attempt <= wikiLLMMaxAttempts; attempt++ {
response, callErr := chatModel.Chat(ctx, messages, opts)
if callErr == nil && response != nil {
return response.Content, nil
}
if callErr == nil {
callErr = errors.New("LLM returned nil response")
}
lastErr = callErr
if !isTransientLLMError(ctx, callErr) {
return "", fmt.Errorf("LLM call failed: %w", callErr)
}
if attempt == wikiLLMMaxAttempts {
break
}
backoff := wikiLLMBackoffBase << (attempt - 1)
logger.Warnf(ctx, "wiki ingest: LLM call failed (attempt %d/%d), retrying in %s: %v",
attempt, wikiLLMMaxAttempts, backoff, callErr)
timer := time.NewTimer(backoff)
select {
case <-ctx.Done():
timer.Stop()
return "", fmt.Errorf("LLM call aborted during backoff: %w", ctx.Err())View on GitHub (pinned to 988cbb0330)
Solutions
- Inspect the chat model adapter: ensure it returns an error instead of (nil, nil) when the provider response is empty.
- Log/inspect the raw provider response to see why no content object was produced.
- Check model/endpoint configuration (correct model name, API key, base URL) so the provider returns a real completion.
- Upgrade or patch the LLM client library if a known bug returns nil responses on certain payloads.
Example fix
// before (adapter)
resp, err := provider.Complete(ctx, req)
return resp, err // resp may be nil with err == nil
// after
resp, err := provider.Complete(ctx, req)
if err != nil { return nil, err }
if resp == nil { return nil, errors.New("provider returned empty response") }
return resp, nil Defensive patterns
Strategy: retry
Validate before calling
response, err := chatModel.Chat(ctx, messages, opts)
if err == nil && response == nil {
err = errors.New("LLM returned nil response")
}
if err != nil && isTransientLLMError(ctx, err) { /* retry */ } Try / catch
// treat nil response as failure and retry transient cases
if callErr == nil { callErr = errors.New("LLM returned nil response") }
if !isTransientLLMError(ctx, callErr) {
return "", fmt.Errorf("LLM call failed: %w", callErr)
} Prevention
- Ensure the chat model adapter always returns an error with a nil response.
- Log raw provider responses to catch empty 200 bodies early.
- Keep wikiLLMMaxAttempts retry coverage for transient provider hiccups.
When it happens
Trigger: chatModel.Chat(ctx, messages, opts) returning (nil, nil) — e.g. an adapter implementation that swallows errors and returns nil on empty/odd provider responses — during any wiki LLM generation call, retried up to wikiLLMMaxAttempts.
Common situations: Provider returns HTTP 200 with an empty body and the adapter maps that to (nil, nil); misconfigured model endpoint returning unexpected payloads; adapter version change altering return semantics.
Related errors
- failed to generate questions: %w
- model is currently downloading
- concurrent wiki task active
- enqueue wiki ingest trigger: task enqueuer is nil
- wiki page slug is required
AI-assisted analysis of Tencent/WeKnora@988cbb0330 (2026-09-02).
Data as JSON: /api/errors/26a419ddceb77290.
Report an issue: GitHub.