{"record":{"id":"4793036a49e21ddc","repo":"danny-avila/LibreChat","slug":"file-path-changed-while-being-read-from-the-s","errorCode":null,"errorMessage":"\"${file_path}\" changed while being read from the sandbox","messagePattern":"\"(.+?)\" changed while being read from the sandbox","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"api/server/services/Files/Code/process.js","lineNumber":1313,"sourceCode":"    if (parsed.error) {\n      throw new Error(String(parsed.error));\n    }\n    if (parsed.too_large === true) {\n      return { tooLarge: true, bytes: Number(parsed.bytes) || 0 };\n    }\n    if (typeof parsed.b64 !== 'string' || typeof parsed.n !== 'number') {\n      return null;\n    }\n\n    if (total == null) {\n      total = Number(parsed.total) || 0;\n      if (total > limit) {\n        return { tooLarge: true, bytes: total };\n      }\n    } else if (Number(parsed.total) !== total) {\n      /* The file changed underneath us; a spliced-together buffer would be\n       * a mix of two versions rather than any real image. */\n      throw new Error(`\"${file_path}\" changed while being read from the sandbox`);\n    }\n\n    parts.push(Buffer.from(parsed.b64, 'base64'));\n    offset += parsed.n;\n\n    if (parsed.n === 0 || offset >= total) {\n      break;\n    }\n  }\n\n  const buffer = Buffer.concat(parts);\n  if (total == null) {\n    return null;\n  }\n  if (buffer.length !== total) {\n    /* Ran out of chunk budget (or short reads); returning a partial image\n     * would render as a corrupt file, so surface it as unreadable-inline. */\n    return { tooLarge: true, bytes: total };","sourceCodeStart":1295,"sourceCodeEnd":1331,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/api/server/services/Files/Code/process.js#L1295-L1331","documentation":"Thrown by the chunked image reader (Code/process.js) when the file's total byte count changed between chunks — i.e. parsed.total on a later chunk differs from the total captured on the first chunk. Splicing the buffers would mix two versions of the file, so the read aborts rather than return corrupt data.","triggerScenarios":"A concurrent process in the sandbox is writing/appending the file while the multi-chunk base64 read is in flight; the file was replaced between two chunk requests.","commonSituations":"An agent tool is logging/appending to the same file the read_file handler is reading; an output redirect overwrote the file mid-read; the sandbox re-used a path across runs.","solutions":["Retry the read when the file is quiescent — ensure no concurrent writer is appending to the same path.","If the file is expected to grow, snapshot it (cp) in the sandbox before reading the snapshot.","Use a stable, write-once filename convention for agent outputs to avoid in-flight mutation."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  const img = await readSandboxImage({ file_path, session_id, req });\n} catch (err) {\n  if (/changed while being read/.test(err.message)) {\n    // snapshot then read the snapshot\n    return readSandboxImage({ file_path: `${file_path}.snap`, session_id, req });\n  }\n  throw err;\n}","preventionTips":["Avoid concurrent appends to files being read — use write-once filenames.","Snapshot (cp) append-prone files in the sandbox before reading.","Retry once when the file is expected to stabilize."],"tags":["code-env","sandbox","image","concurrency","integrity"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}