vxcontrol/pentagi · error · RetryableError
internal engine: summarization failed: %w
Error message
internal engine: summarization failed: %w
What it means
After pages are fetched, the internal engine builds a prompt (`buildPrompt`) and calls `e.summarizer(ctx, prompt)` — an LLM call that synthesizes the answer. If the summarizer returns an error, it is wrapped as Retryable with this message (backend/pkg/tools/searchers/internal.go:178), since an LLM outage is usually transient and the orchestrator can retry or fall back.
Source
Thrown at backend/pkg/tools/searchers/internal.go:178
// [Source N]; usedURLs tracks the matching URL so it can be listed at the end.
blocks = append(blocks, fmt.Sprintf("<source id=\"%d\" url=\"%s\">\n%s\n</source>", fetched+1, u, md))
usedURLs = append(usedURLs, u)
fetched++
}
if fetched == 0 {
// Nothing could be read. If the pages errored (vs. returned empty), surface a
// retryable error so the orchestrator can fall back to another engine.
if lastFetch != nil {
return "", Retryable(fmt.Errorf("internal engine: all pages failed to fetch: %w", lastFetch), 0)
}
return "", Fatal(fmt.Errorf("internal engine: no readable content found"))
}
prompt := e.buildPrompt(req.Query, blocks)
answer, serr := e.summarizer(ctx, prompt)
if serr != nil {
return "", Retryable(fmt.Errorf("internal engine: summarization failed: %w", serr), 0)
}
return appendSources(answer, usedURLs), nil
}
// appendSources appends the list of source URLs the answer was synthesized from, so the
// [Source N] citations in the summary can be traced back to the page they came from. The
// numbering matches the source ids fed to the summarizer (1-based, in fetch order).
func appendSources(answer string, urls []string) string {
if len(urls) == 0 {
return answer
}
var sb strings.Builder
sb.WriteString(strings.TrimRight(answer, "\n"))
sb.WriteString("\n\n### Sources\n\n")
for i, u := range urls {
parsedURL, err := url.Parse(u)
if err != nil {View on GitHub (pinned to ea665308ba)
Solutions
- Check the wrapped cause in the error message — it carries the provider's own error (401/429/5xx/timeout) and fix that specifically
- Verify at least one valid LLM provider key is configured in .env / Settings UI
- Retry — the error is typed Retryable, so transient provider failures are recoverable
- Lower WebSearchInternalMaxSiteBytes (or WebSearchInternalMaxSites) to shrink the prompt if it is exceeding the model's context window
Example fix
// before: prompt too large for the model WEB_SEARCH_INTERNAL_MAX_SITE_BYTES=1000000 // after WEB_SEARCH_INTERNAL_MAX_SITE_BYTES=100000
Defensive patterns
Strategy: retry
Validate before calling
// ensure a summarizer-capable provider is configured before invoking
if cfg.PrimaryProviderAPIKey == "" {
return errors.New("no LLM provider configured for internal search summarizer")
} Try / catch
_, err := engine.Handle(ctx, req)
if err != nil {
if searchers.IsRetryable(err) {
// backoff and retry; check wrapped provider error for 401/429/5xx
}
} Prevention
- Configure and validate at least one LLM provider key at startup
- Watch provider quota/billing; 429s surface as this error
- Cap WebSearchInternalMaxSites/MaxSiteBytes so prompts stay within the model context window
- Add provider health checks in observability dashboards
When it happens
Trigger: The LLM backing the internal engine's summarizer fails: provider API key invalid/quota exhausted, model unavailable, request context deadline exceeded, rate limit (429), or the provider returns 5xx.
Common situations: No LLM provider key configured (or only optional ones set); provider quota/billing exhausted mid-run; LLM provider outage; context window exceeded because the fetched pages were large (WebSearchInternalMaxSiteBytes set too high).
Related errors
- failed to generate subtasks for task %d: %w
- summarization failed: %w
- failed to test provider: %w
- failed to call llm after %d retries: %w
- failed to get active task input: %w
AI-assisted analysis of vxcontrol/pentagi@ea665308ba (2026-09-01).
Data as JSON: /api/errors/cdd0fc975adaaaa5.
Report an issue: GitHub.