Skip to content

A failed embedding is reported to the agent as an empty knowledge base — the one failure RAG cannot afford to state as a fact #628

Description

@serge-ivo

search_knowledge answers a broken embedder with the sentence "the knowledge base may be empty". That sentence is a fabricated explanation of an infrastructure failure, and it is the one the model reads.

The path (all verified)

embed() swallows everything:

// workers/api/src/agent-storage/vectors.ts:304
protected async embed(text: string): Promise<number[] | null> {
    if (!this.ai) return null;
    try { ... } catch { return null; }   // :320-322
}

grep -in "log\|error\|console" workers/api/src/agent-storage/vectors.ts returns 0 lines inside embed — a Workers-AI outage, a rate-limit, a 500 from the model gateway all become null with nothing written to the error log, the trace, or the console.

vectorSearch turns that null into "no matches":

// vectors.ts:106-109
if (!this.vectorize || !this.ai) return [];
const embedding = await this.embed(query);
if (!embedding) return [];

Two callers consume that empty array, and both state it as a fact about the user's data:

  1. The tool. workers/api/src/lib/storage-tools.ts:262-267
    if (results.length === 0) return ok(call.name, "No relevant results found. The knowledge base may be empty or the query didn't match any stored content.")
    Note ok(...), not fail(...). The model is told the search succeeded and found nothing.

  2. The prompt. workers/api/src/agent-storage/context.ts:71-72
    const results = await this.vectorSearch(query, 8); if (results.length > 0) { ... }
    On an empty result the entire ## Relevant Knowledge block is omitted. The turn proceeds ungrounded, and nothing in the prompt, the trace or list_errors says retrieval ran at all.

Why this is the read path's version of a bug the write path already fixed

indexingEnabled exists precisely so this cannot happen on ingest:

// vectors.ts:26-31
 * ... so callers MUST check this before reporting a KB add / repo index as "indexed" 
 * otherwise ingest looks green while RAG is dead (#22).
get indexingEnabled(): boolean { return !!(this.vectorize && this.ai); }

grep -rn "indexingEnabled" workers/api/src — the read path never consults it. #22 stopped ingest lying about indexing; the symmetric lie on retrieval was never closed.

Blast radius (live, read over MCP)

  • Repo Chat (267286d5-6877-4f2a-8b5c-3c40b3e3be85) — vector_stats: 315 sources, 3,979 chunks, 1,823,670 chars. Its declared tools are exactly ["search_knowledge","list_knowledge","read_knowledge"], so search_knowledge is its only route to any of it.
  • Every RAG agent shares buildRAGContext: Doc Chat, Local Repo Chat, Google Drive Doc Chat, the apply agent's KB.

An agent told "the knowledge base may be empty" will report that to the user, and the user will believe their ingest failed.

What "fixed" looks like

Distinguish the search returned nothing from the search did not run. embed() should report its failure (a distinguishable return, plus one logError so it is visible in list_errors), vectorSearch should propagate it rather than flattening to [], search_knowledge should fail(...) with "retrieval is unavailable right now" instead of ok(...) with a claim about the corpus, and buildRAGContext should say retrieval was attempted and failed rather than silently omitting the block.

Verified vs inferred

  • Verified: every line and grep above; the Repo Chat numbers are a live vector_stats read on 2026-08-16.
  • Inferred: the frequency of embed failures in production. Not measurable today — that is the point of the issue: there is no record of one ever having happened.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions