unslothai/unsloth · warning · RuntimeError

Linked source changed during reconciliation

Error message

Linked source changed during reconciliation

What it means

Before copying, _snapshot compares the fstat of the opened descriptor against the metadata recorded during _scan (size, mtime, plus device/inode when comparable — see the identity_from_path caveat in the source). A mismatch means the file's content or identity changed between scan and copy, so the snapshot would be an inconsistent mixture and is rejected.

Source

Thrown at studio/backend/core/rag/folder_sync.py:1044

        target = ensure_dir(rag_uploads_root()) / f"linked-{uuid.uuid4().hex}{ext}"
        before = os.fstat(fd)
        if not stat.S_ISREG(before.st_mode):
            raise RuntimeError("Linked source is not a regular file")
        expected = (
            metadata["size_bytes"],
            metadata["mtime_ns"],
            metadata["device"],
            metadata["inode"],
        )
        actual = (before.st_size, before.st_mtime_ns, before.st_dev, before.st_ino)
        # Only an identity os.fstat can reproduce is comparable here: os.scandir reports none at all
        # on Windows, and the os.lstat _scan falls back to disagrees with os.fstat on file systems
        # without stable file ids. Size and mtime still gate those, and the post-copy check below is
        # fstat to fstat either way.
        usable = metadata["inode"] not in (None, 0) and not metadata.get("identity_from_path")
        compared = 4 if usable else 2
        if actual[:compared] != expected[:compared]:
            raise RuntimeError("Linked source changed during reconciliation")
        if config.MAX_UPLOAD_BYTES and before.st_size > config.MAX_UPLOAD_BYTES:
            raise RuntimeError("Linked source exceeds the RAG file size limit")
        with os.fdopen(fd, "rb", closefd = False) as src, open(target, "xb") as dst:
            _copy_exact(src, dst, before.st_size)
        after = os.fstat(fd)
        # Both sides are fstat here, so the identity is always comparable.
        if (after.st_size, after.st_mtime_ns, after.st_dev, after.st_ino) != actual:
            raise RuntimeError("Linked source changed while it was copied")
        return str(target)
    except Exception:
        if target is not None:
            _remove_snapshot(str(target))
        raise
    finally:
        os.close(fd)


def _copy_exact(source, target, size: int) -> None:

View on GitHub (pinned to 203007d190)

Solutions

  1. Wait for writes to finish and re-run sync; the next cycle reconciles the settled state.
  2. Sync during quiescent windows (cron at night, post-build) rather than while files stream in.
  3. Exclude hot directories (logs, downloads-in-progress) from the linked root.
Defensive patterns

Strategy: retry

Validate before calling

import os

def file_is_quiet(metadata: dict) -> bool:
    st = os.stat(metadata["path"])
    return (st.st_size, st.st_mtime_ns) == (metadata["size_bytes"], metadata["mtime_ns"])

Try / catch

try:
    reconcile(folder_id)
except RuntimeError as e:
    if "changed during reconciliation" in str(e):
        wait_for_writers_to_settle(folder_id)
        reconcile(folder_id)  # next pass snapshots the settled file
    else:
        raise

Prevention

When it happens

Trigger: A file is appended to, truncated, touched, or rewritten (new inode) after _scan but before _snapshot processes it — typically during active write workloads on the linked folder (logs being written, editors saving, CI output).

Common situations: Linking a folder that applications actively write to; syncing while a big copy/download into the folder is in progress; editors using atomic replace (new inode) on every save.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/51583337d23ef7f1. Report an issue: GitHub.