{"record":{"id":"639f6feeeabaedef","repo":"unslothai/unsloth","slug":"linked-folder-changed-while-it-was-reauthorized","errorCode":null,"errorMessage":"Linked folder changed while it was reauthorized","messagePattern":"Linked folder changed while it was reauthorized","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"studio/backend/core/rag/folder_sync.py","lineNumber":309,"sourceCode":"        except Exception:\n            conn.rollback()\n            raise\n        finally:\n            conn.close()\n\n\ndef _reauthorize_folder(\n    folder_id: str, path: str, expected_identity: tuple[int, int] | None\n) -> dict:\n    with _folder_lock(folder_id):\n        conn = rag_db.get_connection()\n        try:\n            conn.execute(\"BEGIN IMMEDIATE\")\n            if (\n                conn.execute(\"SELECT 1 FROM linked_folders WHERE id=?\", (folder_id,)).fetchone()\n                is None\n            ):\n                raise ValueError(\"Linked folder changed while it was reauthorized\")\n            try:\n                identity = _root_identity(path)\n            except RuntimeError as exc:\n                raise ValueError(str(exc)) from exc\n            if expected_identity is not None and identity != expected_identity:\n                raise ValueError(\"Linked folder changed after it was selected\")\n            conn.execute(\n                \"UPDATE linked_folders SET root_device=?, root_inode=?, updated_at=? WHERE id=?\",\n                (*_store_identity(identity), _now(), folder_id),\n            )\n            conn.commit()\n            return dict(\n                conn.execute(\"SELECT * FROM linked_folders WHERE id=?\", (folder_id,)).fetchone()\n            )\n        except Exception:\n            conn.rollback()\n            raise\n        finally:","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/rag/folder_sync.py#L291-L327","documentation":"In _reauthorize_folder (reached from create_folder when the path matches an existing active row), after taking BEGIN IMMEDIATE the linked_folders row with that id no longer exists. Between the outer duplicate-detection read and this inner transaction, another thread removed/deleted the row, so re-authorization has nothing to update.","triggerScenarios":"Concurrent create_folder and remove_folder for the same path/scope on different threads: outer transaction rolls back to call _reauthorize_folder, meanwhile the row is deleted (retire completes) before its BEGIN IMMEDIATE runs.","commonSituations":"Double-click / double-submit races between add and remove in the UI; a background reconciliation deleting stale rows while a user re-links the same folder.","solutions":["Retry create_folder: with the old row gone, it will now take the plain INSERT path.","Catch the ValueError at the call site and treat it as 'retry once', not as a permanent failure.","Avoid firing add and remove for the same path concurrently from the client."],"exampleFix":"# before\nfolder = create_folder(...)\n\n# after\nfor attempt in range(2):\n    try:\n        folder = create_folder(...)\n        break\n    except ValueError as e:\n        if \"reauthorized\" not in str(e) or attempt == 1:\n            raise","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    folder = create_folder(...)\nexcept ValueError as e:\n    if \"changed while it was reauthorized\" in str(e):\n        folder = create_folder(...)  # row vanished; plain INSERT path now applies\n    else:\n        raise","preventionTips":["Serialize add/remove operations for the same scope in the client.","Treat this as a transient race: one retry is nearly always sufficient.","Log occurrences to find UI paths that fire concurrent add+remove."],"tags":["rag","folder-sync","race-condition","retryable"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}