{"record":{"id":"26a419ddceb77290","repo":"Tencent/WeKnora","slug":"llm-returned-nil-response","errorCode":null,"errorMessage":"LLM returned nil response","messagePattern":"LLM returned nil response","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/wiki_ingest.go","lineNumber":2588,"sourceCode":"\texecute := func() (interface{}, error) {\n\t\treleaseWarmup := func() {}\n\t\tif tenantScoped && promptTpl == agent.WikiPageModifyUserPrompt && strings.TrimSpace(maskedData[\"SharedSourceContexts\"]) != \"\" {\n\t\t\tvar warmupErr error\n\t\t\treleaseWarmup, warmupErr = s.awaitWikiPromptWarmup(ctx, warmupKey)\n\t\t\tif warmupErr != nil {\n\t\t\t\treturn \"\", warmupErr\n\t\t\t}\n\t\t}\n\t\tdefer releaseWarmup()\n\n\t\tvar lastErr error\n\t\tfor attempt := 1; attempt <= wikiLLMMaxAttempts; attempt++ {\n\t\t\tresponse, callErr := chatModel.Chat(ctx, messages, opts)\n\t\t\tif callErr == nil && response != nil {\n\t\t\t\treturn response.Content, nil\n\t\t\t}\n\t\t\tif callErr == nil {\n\t\t\t\tcallErr = errors.New(\"LLM returned nil response\")\n\t\t\t}\n\t\t\tlastErr = callErr\n\n\t\t\tif !isTransientLLMError(ctx, callErr) {\n\t\t\t\treturn \"\", fmt.Errorf(\"LLM call failed: %w\", callErr)\n\t\t\t}\n\t\t\tif attempt == wikiLLMMaxAttempts {\n\t\t\t\tbreak\n\t\t\t}\n\n\t\t\tbackoff := wikiLLMBackoffBase << (attempt - 1)\n\t\t\tlogger.Warnf(ctx, \"wiki ingest: LLM call failed (attempt %d/%d), retrying in %s: %v\",\n\t\t\t\tattempt, wikiLLMMaxAttempts, backoff, callErr)\n\t\t\ttimer := time.NewTimer(backoff)\n\t\t\tselect {\n\t\t\tcase <-ctx.Done():\n\t\t\t\ttimer.Stop()\n\t\t\t\treturn \"\", fmt.Errorf(\"LLM call aborted during backoff: %w\", ctx.Err())","sourceCodeStart":2570,"sourceCodeEnd":2606,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/wiki_ingest.go#L2570-L2606","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before (adapter)\nresp, err := provider.Complete(ctx, req)\nreturn resp, err // resp may be nil with err == nil\n// after\nresp, err := provider.Complete(ctx, req)\nif err != nil { return nil, err }\nif resp == nil { return nil, errors.New(\"provider returned empty response\") }\nreturn resp, nil","handlingStrategy":"retry","validationCode":"response, err := chatModel.Chat(ctx, messages, opts)\nif err == nil && response == nil {\n    err = errors.New(\"LLM returned nil response\")\n}\nif err != nil && isTransientLLMError(ctx, err) { /* retry */ }","typeGuard":null,"tryCatchPattern":"// treat nil response as failure and retry transient cases\nif callErr == nil { callErr = errors.New(\"LLM returned nil response\") }\nif !isTransientLLMError(ctx, callErr) {\n    return \"\", fmt.Errorf(\"LLM call failed: %w\", callErr)\n}","preventionTips":["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."],"tags":["llm","nil-response","retry","wiki"],"backgroundTag":"llm-empty-response","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}