unslothai/unsloth · error · HTTPException

Could not update '{folder.name}' with the imported example (

Error message

Could not update '{folder.name}' with the imported example ({getattr(e, 'strerror', None) or e}). Nothing was written; try again.

What it means

HTTP 409 from the import route's atomic promotion phase: after a successful materialization into staging, folding the old folder's files and os.replace(staging -> folder) failed with OSError/shutil.Error. Causes include an unmovable entry (permissions, file held open, Windows antivirus holding the rename), or a file appearing in the folder mid-move. The handler runs restore_folded() to put pre-existing entries back, then reports 'Nothing was written; try again' — the dataset folder is restored to its pre-import state.

Source

Thrown at studio/backend/routes/training.py:4294

                if imported == 0:
                    raise HTTPException(
                        status_code = 502,
                        detail = f"No images found in '{entry['repo']}'.",
                    )
                # Promote the fully-materialized staging dir as a UNIT: a same-filesystem rename is atomic, so a hard process death
                # leaves either the old folder or the finished import. rmdir needs an empty target, so fold any pre-existing files (a .thumbs cache, an older metadata.jsonl) INTO staging first and keep one atomic promotion.
                try:
                    for p in sorted(folder.iterdir()):
                        # Same name in both: the imported file wins, as the previous per-file move did. Park the old one in the rescue dir so the folder can be emptied for the rename without destroying it.
                        dest = (rescue if (staging / p.name).exists() else staging) / p.name
                        shutil.move(str(p), str(dest))
                        folded.append((dest, p))
                    os.rmdir(folder)
                    os.replace(str(staging), str(folder))
                except (OSError, shutil.Error) as e:
                    # Every step here can fail (an unmovable entry, a folder that gained a file, a rename held by antivirus), and by then the folder's entries live only in the staging/rescue dirs the finally deletes.
                    restore_folded()
                    raise HTTPException(
                        status_code = 409,
                        detail = (
                            f"Could not update '{folder.name}' with the imported example "
                            f"({getattr(e, 'strerror', None) or e}). Nothing was written; try again."
                        ),
                    )
            finally:
                shutil.rmtree(staging, ignore_errors = True)
                shutil.rmtree(rescue, ignore_errors = True)
        return _import_response(entry, folder, imported = imported)

    return await asyncio.to_thread(do_import)

View on GitHub (pinned to 203007d190)

Solutions

  1. Simply retry the import — the message says nothing was written, and the restore path keeps the folder consistent; transient locks (AV scan finishing) clear on their own.
  2. Close other Studio tabs / labeling sessions using that dataset, then retry.
  3. Fix permissions on the datasets root and ensure it is on a local filesystem; add AV exclusions for the datasets directory.
  4. If it keeps failing on Windows, exclude the Studio datasets folder from real-time antivirus scanning.

Example fix

# ensure writable, local, and not contended
chmod -R u+w /studio/datasets/myset
lsof +D /studio/datasets/myset   # find holders on POSIX
Defensive patterns

Strategy: retry

Validate before calling

import os
from pathlib import Path

def folder_promotable(folder: Path) -> bool:
    try:
        probe = folder / '.promote-probe'
        probe.write_text('')
        probe.unlink()
        return os.access(folder, os.W_OK | os.X_OK)
    except OSError:
        return False

Type guard

def is_promotion_failure(exc: HTTPException) -> bool:
    return exc.status_code == 409 and 'Could not update' in str(exc.detail)

Try / catch

for attempt in range(3):
    try:
        resp = await api.importExample(ex.id)
        break
    except HTTPStatusError as e:
        if e.response.status_code == 409 and 'Could not update' in e.response.text:
            await backoff(attempt)  # AV/lock often clears; folder was restored intact
            continue
        raise

Prevention

When it happens

Trigger: The import succeeded in fetching everything, then: a permissions error moving a .thumbs cache file, an OS-level rename failure (Windows file lock by antivirus/indexer/another process), or a concurrent writer adding a file to the folder between the emptiness check and the promotion.

Common situations: Windows AV scanning newly written staging files during promotion; network filesystems (NFS/SMB) where rename over an existing dir is not atomic or fails; another session writing captions/thumbnails into the folder during the import; restrictive permissions on the datasets root.

Related errors


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