{"record":{"id":"609fc753985f876a","repo":"unslothai/unsloth","slug":"could-not-update-folder-name-with-the-imported","errorCode":null,"errorMessage":"Could not update '{folder.name}' with the imported example ({getattr(e, 'strerror', None) or e}). Nothing was written; try again.","messagePattern":"Could not update '(.+?)' with the imported example \\((.+?)\\)\\. Nothing was written; try again\\.","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"error","filePath":"studio/backend/routes/training.py","lineNumber":4294,"sourceCode":"                if imported == 0:\n                    raise HTTPException(\n                        status_code = 502,\n                        detail = f\"No images found in '{entry['repo']}'.\",\n                    )\n                # Promote the fully-materialized staging dir as a UNIT: a same-filesystem rename is atomic, so a hard process death\n                # 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.\n                try:\n                    for p in sorted(folder.iterdir()):\n                        # 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.\n                        dest = (rescue if (staging / p.name).exists() else staging) / p.name\n                        shutil.move(str(p), str(dest))\n                        folded.append((dest, p))\n                    os.rmdir(folder)\n                    os.replace(str(staging), str(folder))\n                except (OSError, shutil.Error) as e:\n                    # 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.\n                    restore_folded()\n                    raise HTTPException(\n                        status_code = 409,\n                        detail = (\n                            f\"Could not update '{folder.name}' with the imported example \"\n                            f\"({getattr(e, 'strerror', None) or e}). Nothing was written; try again.\"\n                        ),\n                    )\n            finally:\n                shutil.rmtree(staging, ignore_errors = True)\n                shutil.rmtree(rescue, ignore_errors = True)\n        return _import_response(entry, folder, imported = imported)\n\n    return await asyncio.to_thread(do_import)\n","sourceCodeStart":4276,"sourceCodeEnd":4307,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/training.py#L4276-L4307","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["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.","Close other Studio tabs / labeling sessions using that dataset, then retry.","Fix permissions on the datasets root and ensure it is on a local filesystem; add AV exclusions for the datasets directory.","If it keeps failing on Windows, exclude the Studio datasets folder from real-time antivirus scanning."],"exampleFix":"# ensure writable, local, and not contended\nchmod -R u+w /studio/datasets/myset\nlsof +D /studio/datasets/myset   # find holders on POSIX","handlingStrategy":"retry","validationCode":"import os\nfrom pathlib import Path\n\ndef folder_promotable(folder: Path) -> bool:\n    try:\n        probe = folder / '.promote-probe'\n        probe.write_text('')\n        probe.unlink()\n        return os.access(folder, os.W_OK | os.X_OK)\n    except OSError:\n        return False","typeGuard":"def is_promotion_failure(exc: HTTPException) -> bool:\n    return exc.status_code == 409 and 'Could not update' in str(exc.detail)","tryCatchPattern":"for attempt in range(3):\n    try:\n        resp = await api.importExample(ex.id)\n        break\n    except HTTPStatusError as e:\n        if e.response.status_code == 409 and 'Could not update' in e.response.text:\n            await backoff(attempt)  # AV/lock often clears; folder was restored intact\n            continue\n        raise","preventionTips":["Retry 409 'Could not update' after a short delay — the restore path leaves the folder consistent, so retry is safe.","Keep datasets on a local filesystem; avoid NFS/SMB for the datasets root.","Add AV exclusions for the datasets directory on Windows.","Do not edit a dataset (captions, thumbnails) while an example import into it is running."],"tags":["filesystem","atomic-write","windows","import","http-409"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}