{"record":{"id":"fd50ca2aea0e0650","repo":"mastra-ai/mastra","slug":"unable-to-read-worker-stream","errorCode":null,"errorMessage":"Unable to read worker ${stream}.","messagePattern":"Unable to read worker (.+?)\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"deployers/sandbox/src/worker.ts","lineNumber":679,"sourceCode":"  sandbox: WorkspaceSandbox,\n  executionId: string,\n  resolvePaths: () => Promise<ReturnType<typeof executionPaths>>,\n  stream: 'stdout' | 'stderr',\n  options?: { offset?: number; maxBytes?: number },\n): Promise<SandboxWorkerOutput> {\n  const offset = Math.max(0, Math.floor(options?.offset ?? 0));\n  const maxBytes = Math.max(1, Math.floor(options?.maxBytes ?? DEFAULT_OUTPUT_READ_LIMIT));\n  try {\n    const paths = await resolvePaths();\n    const path = stream === 'stdout' ? paths.stdout : paths.stderr;\n    const result = await runInSandbox(\n      sandbox,\n      `size=$(wc -c < ${shellQuote(path)} 2>/dev/null || echo 0); printf '%s\\\\n' \"$size\"; tail -c +${offset + 1} ${shellQuote(\n        path,\n      )} 2>/dev/null | head -c ${maxBytes} | base64`,\n      { allowFailure: true, label: `read worker ${stream}` },\n    );\n    if (result.exitCode !== 0) throw new Error(result.stderr || result.stdout || `Unable to read worker ${stream}.`);\n    const newline = result.stdout.indexOf('\\n');\n    const totalBytes = Number((newline === -1 ? result.stdout : result.stdout.slice(0, newline)).trim()) || 0;\n    const encoded = newline === -1 ? '' : result.stdout.slice(newline + 1).replace(/\\s/g, '');\n    const data = Buffer.from(encoded, 'base64');\n    const nextOffset = offset + data.byteLength;\n    const status = await readWorkerStatus(sandbox, executionId, resolvePaths);\n    const terminal = ['exited', 'resource_exhausted', 'cancelled', 'timed_out', 'failed'].includes(status.state);\n    const interrupted = status.state === 'provider_unavailable' || status.state === 'unknown';\n    return {\n      stream,\n      data,\n      offset,\n      nextOffset,\n      totalBytes,\n      eof: terminal && nextOffset >= totalBytes,\n      truncated: nextOffset < totalBytes,\n      interrupted,\n    };","sourceCodeStart":661,"sourceCodeEnd":697,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/deployers/sandbox/src/worker.ts#L661-L697","documentation":"readOutput tails a worker output stream file inside the sandbox over a shell command (wc -c + tail + base64). If the command exits non-zero and neither stderr nor stdout carries a usable message, the library throws this generic 'Unable to read worker <stream>' error indicating the output file could not be read.","triggerScenarios":"Calling workerDeployment.output(...) / readOutput when the shell read fails: output file path missing or unreadable under the resolved paths, sandbox command execution failing (permissions, dead sandbox), or the provider returning a non-zero exit code for the read command.","commonSituations":"Worker never created the output file because it crashed before writing; incorrect remoteDir/paths resolution; sandbox restarted and tmp files wiped; restrictive file permissions (note stageInput chmods input 600 — analogous permission issues on output); sandbox provider connectivity flakiness.","solutions":["Check result.stderr in the error message (it is preferred over stdout) — it usually contains the shell-level failure reason.","Verify the worker actually ran and produced the output file at the resolved path (inspect sandbox filesystem).","Confirm remoteDir/execution paths resolve to the expected location in the sandbox config.","Check sandbox file permissions on the output file and the sandbox process's liveness.","Retry the read; transient provider failures can make the shell command exit non-zero."],"exampleFix":"// before\nconst { data } = await worker.output('stdout', { offset });\n// after\ntry {\n  const { data } = await worker.output('stdout', { offset });\n} catch (e) {\n  if (String(e).includes('Unable to read worker')) {\n    const status = await worker.status();\n    if (status.state !== 'running') throw new Error(`Worker not running: ${status.state}`);\n  }\n  throw e;\n}","handlingStrategy":"retry","validationCode":"// before reading output, confirm the worker is alive and paths resolve\nconst status = await worker.status();\nif (status.state === 'failed' || status.state === 'canceled') throw new Error('worker not producing output: ' + status.state);","typeGuard":"function workerCanProduceOutput(status) { return status != null && ['running', 'completed', 'succeeded'].includes(status.state); }","tryCatchPattern":"try {\n  const out = await worker.output(stream, { offset });\n} catch (e) {\n  if (/Unable to read worker/.test(e.message)) {\n    await sleep(backoff);\n    return worker.output(stream, { offset }); // bounded retry for transient provider failures\n  } else throw e;\n}","preventionTips":["Ensure the worker creates/opens output stream files early so reads don't hit missing paths.","Verify remoteDir and execution path resolution in config against the real sandbox layout.","Use bounded retries with backoff for transient shell/provider failures.","Confirm sandbox file permissions allow the reading user to access output files.","Check worker status before reading output to distinguish crash from transport failure."],"tags":["sandbox","file-io","output-stream","shell"],"backgroundTag":"file-read-failed","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T03:17:51.788Z"}