{"record":{"id":"084b6019010c79ff","repo":"denoland/deno","slug":"file-busy","errorCode":null,"errorMessage":"file busy","messagePattern":"file busy","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"ext/io/fs.rs","lineNumber":71,"sourceCode":"}\n\nimpl std::error::Error for FsError {}\n\nimpl FsError {\n  pub fn kind(&self) -> io::ErrorKind {\n    match self {\n      Self::Io(err) => err.kind(),\n      Self::FileBusy => io::ErrorKind::Other,\n      Self::NotSupported => io::ErrorKind::Other,\n      Self::PermissionCheck(e) => e.kind(),\n      Self::JoinError(_) => io::ErrorKind::Other,\n    }\n  }\n\n  pub fn into_io_error(self) -> io::Error {\n    match self {\n      FsError::Io(err) => err,\n      FsError::FileBusy => io::Error::new(self.kind(), \"file busy\"),\n      FsError::NotSupported => io::Error::new(self.kind(), \"not supported\"),\n      FsError::PermissionCheck(err) => err.into_io_error(),\n      FsError::JoinError(ref err) => {\n        io::Error::new(self.kind(), format!(\"join error: {err}\"))\n      }\n    }\n  }\n}\n\nimpl From<io::Error> for FsError {\n  fn from(err: io::Error) -> Self {\n    Self::Io(err)\n  }\n}\n\nimpl From<io::ErrorKind> for FsError {\n  fn from(err: io::ErrorKind) -> Self {\n    Self::Io(err.into())","sourceCodeStart":53,"sourceCodeEnd":89,"githubUrl":"https://github.com/denoland/deno/blob/9ad36f7a2cce60488e6ec52283efb32efddaf93a/ext/io/fs.rs#L53-L89","documentation":"Each stdio/FsFile resource is guarded by a RefCell<Option<StdFile>> permitting one operation at a time. Synchronous ops go through with_sync(), which uses try_borrow_mut(); when the cell is held — typically because an async read/write/seek on the same rid is still in flight, or the file was temporarily taken out for a blocking task — the op returns FsError::FileBusy, surfaced in JS as a 'Busy' error (io::ErrorKind::Other) with message 'file busy' (ext/io/fs.rs:71).","triggerScenarios":"file.readSync()/writeSync()/seekSync() on a Deno.FsFile while an async file.read()/write()/... on the same handle has not resolved; issuing a sync op between starting an async op and awaiting it; cloning the resource while a blocking task owns it.","commonSituations":"Piping a file to stdout while concurrently polling it; libraries mixing sync and async fs APIs on one handle; wrapping the same rid in two abstractions that both act on it.","solutions":["Await all in-flight async ops on the handle before calling its sync methods","Open a second handle (Deno.open) for genuinely concurrent access","Pick one style — all sync or all async — per handle","Catch 'Busy' and retry once after the pending async work drains"],"exampleFix":"// before\nconst p = file.read(buf);      // async op in flight\nconst n = file.readSync(buf);  // Error: file busy\n\n// after\nconst p = file.read(buf);\nconst n = await p;\nconst m = file.readSync(buf); // safe: no pending async op","handlingStrategy":"retry","validationCode":"// Serialize all access through one queue so sync ops never race async ops\nconst pending: Promise<unknown>[] = [];\nfunction serialized<T>(op: () => Promise<T>): Promise<T> {\n  const p = (async () => {\n    await Promise.all(pending.splice(0));\n    return op();\n  })();\n  pending.push(p);\n  return p;\n}\nconst n = await serialized(() => file.read(buf));","typeGuard":null,"tryCatchPattern":"function isBusy(e: unknown): boolean {\n  return e instanceof Error && e.name === 'Busy' && /file busy/.test(e.message);\n}\n\nlet n: number;\nfor (let i = 0; ; i++) {\n  try {\n    n = file.readSync(buf);\n    break;\n  } catch (e) {\n    if (i < 2 && isBusy(e)) {\n      await new Promise((r) => setTimeout(r, 10)); // let the async op finish\n      continue;\n    }\n    throw e;\n  }\n}","preventionTips":["Await every async op on a handle before calling its sync methods","Choose all-sync or all-async per file handle, never both","Open a second handle for genuinely concurrent access"],"tags":["filesystem","concurrency","sync-vs-async","resource","deno"],"backgroundTag":"concurrent-file-access","analyzedSha":"9ad36f7a2cce60488e6ec52283efb32efddaf93a","analyzedAt":"2026-08-20T13:07:44.778Z","contentChangedAt":"2026-08-20T13:07:44.778Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}