infiniflow/ragflow · error · RuntimeError

Database error (File retrieval)!

Error message

Database error (File retrieval)!

What it means

RuntimeError from FileService.get_by_pf_id_name when a file row matched by (parent_id, name) but the follow-up get_by_id on its id returns not-found. It signals an inconsistent read — the row existed for the SELECT then vanished (or get_by_id's filter differs), so the method refuses to return a half-resolved file.

Source

Thrown at api/db/services/file_service.py:171

        kbs_info_list = []
        for kb in list(kbs.dicts()):
            kbs_info_list.append({"kb_id": kb["id"], "kb_name": kb["name"], "document_id": kb["document_id"]})
        return kbs_info_list

    @classmethod
    @DB.connection_context()
    def get_by_pf_id_name(cls, id, name):
        # Get file by parent folder ID and name
        # Args:
        #     id: Parent folder ID
        #     name: File name
        # Returns:
        #     File object or None if not found
        file = cls.model.select().where((cls.model.parent_id == id) & (cls.model.name == name))
        if file.count():
            e, file = cls.get_by_id(file[0].id)
            if not e:
                raise RuntimeError("Database error (File retrieval)!")
            return file
        return None

    @classmethod
    @DB.connection_context()
    def get_id_list_by_id(cls, id, name, count, res):
        # Recursively get list of file IDs by traversing folder structure
        # Args:
        #     id: Starting folder ID
        #     name: List of folder names to traverse
        #     count: Current depth in traversal
        #     res: List to store results
        # Returns:
        #     List of file IDs
        if count < len(name):
            file = cls.get_by_pf_id_name(id, name[count])
            if file:
                res.append(file.id)

View on GitHub (pinned to 554fb1133a)

Solutions

  1. Retry the operation once after re-querying — this is a transient race in most cases.
  2. Avoid deleting and reading the same folder path concurrently; serialize folder mutations per user.
  3. If persistent, inspect the matched row (id, flags) to see why get_by_id rejects it.

Example fix

# before: single attempt
f = FileService.get_by_pf_id_name(folder_id, name)
# after: tolerate the race
for _ in range(2):
    try:
        f = FileService.get_by_pf_id_name(folder_id, name); break
    except RuntimeError:
        continue
Defensive patterns

Strategy: retry

Validate before calling

row = FileService.model.select().where(FileService.model.parent_id == id, FileService.model.name == name)
if not row.count():
    return None  # no conflict — nothing to defend against yet

Try / catch

for attempt in range(2):
    try:
        return FileService.get_by_pf_id_name(id, name)
    except RuntimeError as e:
        if 'File retrieval' not in str(e) or attempt == 1:
            raise
        continue  # row vanished mid-read; re-select

Prevention

When it happens

Trigger: Folder listing/upload-name check racing a delete: select finds the row, deletion commits, get_by_id misses. Also possible when the matched row is filtered out by get_by_id's conditions.

Common situations: Concurrent uploads and deletes in the same folder (two clients); duplicated name check colliding with cleanup jobs; rare in single-user flows.

Related errors


AI-assisted analysis of infiniflow/ragflow@554fb1133a (2026-08-15). Data as JSON: /api/errors/123acb15fdaa5c13. Report an issue: GitHub.