Knowledge Indexing Errors

See which files failed to embed instead of getting a silent empty result

When you index a folder into a knowledge base, Knowledge.add() tells you which files failed so an outage in your embedding backend never looks like a successful import.

Diagram

Indexing a folder

📁 Directory

🔍 Walk files

🧠 Embed each

✅ results

❌ errors

Quick Start

  1. Simple usage

    Point an agent at a folder and ask a question — indexing happens for you.

    python
    from praisonaiagents import Agent
    
    agent = Agent(
        name="Docs Agent",
        instructions="Answer from the docs folder.",
        knowledge=["./docs"],
    )
    
    agent.start("What does the knowledge base cover?")
  2. Check indexing succeeded

    Call add() directly and inspect result["errors"] to see which files failed.

    python
    from praisonaiagents.knowledge import Knowledge
    
    k = Knowledge()
    result = k.add("./docs")
    
    if result["errors"]:
        for e in result["errors"]:
            print(f"failed: {e['file']} — {e['error']}")
    else:
        print(f"indexed {len(result['results'])} chunk(s)")

How It Works

Knowledge.add() walks the directory, embeds each file, and returns the successes and failures together.

Diagram
StoreKnowledgeUserStoreKnowledgeUserloop[Each file]add(“./docs”)store(chunk)stored id or failure{results, relations, errors}

A failed file is recorded instead of dropped, so a directory whose every file fails to embed no longer returns an empty-but-successful result.


Return shape

add() on a directory or list always returns these keys — errors is present even on success (as an empty list).

KeyTypeDescription
resultslistSuccessfully stored chunk records
relationslistGraph relations, when a graph store is configured
errorslist[dict]{'file': str, 'error': str} entries, one per file that failed to index
python
{
    'results': [...],
    'relations': [],
    'errors': [
        {'file': '/abs/path/a.md',
         'error': 'Failed to generate embedding (model=text-embedding-3-small)'},
    ],
}

add([...]) aggregates errors from every input path, so one bad directory never hides errors from another.


Failure modes

All files failed

Every entry lands in errors and results is empty. The log line names the first cause. Common causes: a wrong embedding model name, a revoked API key, or an exhausted quota.

Partial failure

results holds the chunks that succeeded and errors names only the ones that failed. The import is not rolled back.

Partial-chunk loss inside one file

When some of a file’s chunks embed and others are swallowed by the backend, the file still appears in results with the chunks that landed. Only when every chunk of a single-file add() fails does the call raise (see the next accordion) — a partial loss inside one file does not currently raise or add a per-chunk entry to errors.

Guard against silent partial loss by treating a low results count for a large file as suspicious, and re-index the file if the embedding backend was degraded during the run.

Single-file add() where every chunk failed

The single-file path raises instead of returning silently:

RuntimeError: Stored nothing from {path}: all {n} chunk(s) failed (embedding/vector-store backend). See earlier logs.

Wrap the call in try / except RuntimeError if the caller wants to keep going.

List input

add([path1, path2, ...]) aggregates errors from every input path into one errors list.

Durable incremental index

The incremental-index state file (tracker.json) is saved atomically as of PR #5841. If a save fails part-way, the previous state file stays intact.

Before, a failed save could wipe the per-file record of stored chunks. The next incremental index would then treat every file as new and re-add it, leaving the old chunks in the vector store, so agents retrieved duplicate or stale content.

As of PR #6111, an unreadable or corrupt state file no longer resets to an empty state silently. FileTracker.load() logs a WARNING naming the state file and the error, and FileTracker.save() logs write failures instead of swallowing them. The empty-state fallback is unchanged — only the diagnostics are new, so a surprise full re-embed is traceable to its cause.


User interaction flow

Bulk-import a docs folder before deployment, then gate the deploy on the result.

python
from praisonaiagents.knowledge import Knowledge

k = Knowledge()
result = k.add("./docs")

assert not result["errors"], f"{len(result['errors'])} file(s) failed to index"
print(f"indexed {len(result['results'])} chunk(s)")

Run this in CI so a broken embedding backend fails the deploy instead of shipping an empty knowledge base.


Using index()

Knowledge.index() returns an IndexResult whose errors list carries whole-file failures as "{filepath}: {message}" strings.

python
from praisonaiagents.knowledge import Knowledge

k = Knowledge()
result = k.index("./docs")

if not result.errors:
    print(f"indexed {result.files_indexed} file(s)")
else:
    for err in result.errors:
        print(f"failed: {err}")

Common Patterns

Fail fast in CI:

python
from praisonaiagents.knowledge import Knowledge

k = Knowledge()
result = k.add("./docs")
assert not result["errors"]

Report and continue — keep what succeeded, log what didn’t:

python
from praisonaiagents.knowledge import Knowledge

k = Knowledge()
result = k.add("./docs")
for e in result["errors"]:
    print(f"skipped: {e['file']} — {e['error']}")

Retry only the failed files:

python
from praisonaiagents.knowledge import Knowledge

k = Knowledge()
result = k.add("./docs")
for e in result["errors"]:
    k.add(e["file"])

Best Practices

Always inspect result['errors'] after a bulk import

A non-empty errors list is the only reliable signal that a file was skipped. Check it every time you index a folder.

Treat a non-empty errors list as an outage signal

Failures usually mean the embedding backend is down — a wrong model name, a revoked key, or an exhausted quota. Alert on it rather than logging it as a warning.

Catch RuntimeError for single-file calls

The errors list is populated on the directory and list paths. A single-file add() where every chunk fails raises RuntimeError, so wrap it in try / except if you need to continue.

Trust errors whether the backend raised or returned empty

errors is populated whether the store raised an exception or returned an empty result — embedding backends do both, and both are captured.


Related