mastra-ai/mastra · error
Unable to read worker ${stream}.
Error message
Unable to read worker ${stream}. What it means
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.
Source
Thrown at deployers/sandbox/src/worker.ts:679
sandbox: WorkspaceSandbox,
executionId: string,
resolvePaths: () => Promise<ReturnType<typeof executionPaths>>,
stream: 'stdout' | 'stderr',
options?: { offset?: number; maxBytes?: number },
): Promise<SandboxWorkerOutput> {
const offset = Math.max(0, Math.floor(options?.offset ?? 0));
const maxBytes = Math.max(1, Math.floor(options?.maxBytes ?? DEFAULT_OUTPUT_READ_LIMIT));
try {
const paths = await resolvePaths();
const path = stream === 'stdout' ? paths.stdout : paths.stderr;
const result = await runInSandbox(
sandbox,
`size=$(wc -c < ${shellQuote(path)} 2>/dev/null || echo 0); printf '%s\\n' "$size"; tail -c +${offset + 1} ${shellQuote(
path,
)} 2>/dev/null | head -c ${maxBytes} | base64`,
{ allowFailure: true, label: `read worker ${stream}` },
);
if (result.exitCode !== 0) throw new Error(result.stderr || result.stdout || `Unable to read worker ${stream}.`);
const newline = result.stdout.indexOf('\n');
const totalBytes = Number((newline === -1 ? result.stdout : result.stdout.slice(0, newline)).trim()) || 0;
const encoded = newline === -1 ? '' : result.stdout.slice(newline + 1).replace(/\s/g, '');
const data = Buffer.from(encoded, 'base64');
const nextOffset = offset + data.byteLength;
const status = await readWorkerStatus(sandbox, executionId, resolvePaths);
const terminal = ['exited', 'resource_exhausted', 'cancelled', 'timed_out', 'failed'].includes(status.state);
const interrupted = status.state === 'provider_unavailable' || status.state === 'unknown';
return {
stream,
data,
offset,
nextOffset,
totalBytes,
eof: terminal && nextOffset >= totalBytes,
truncated: nextOffset < totalBytes,
interrupted,
};View on GitHub (pinned to 75dd419e61)
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.
Example fix
// before
const { data } = await worker.output('stdout', { offset });
// after
try {
const { data } = await worker.output('stdout', { offset });
} catch (e) {
if (String(e).includes('Unable to read worker')) {
const status = await worker.status();
if (status.state !== 'running') throw new Error(`Worker not running: ${status.state}`);
}
throw e;
} Defensive patterns
Strategy: retry
Validate before calling
// before reading output, confirm the worker is alive and paths resolve
const status = await worker.status();
if (status.state === 'failed' || status.state === 'canceled') throw new Error('worker not producing output: ' + status.state); Type guard
function workerCanProduceOutput(status) { return status != null && ['running', 'completed', 'succeeded'].includes(status.state); } Try / catch
try {
const out = await worker.output(stream, { offset });
} catch (e) {
if (/Unable to read worker/.test(e.message)) {
await sleep(backoff);
return worker.output(stream, { offset }); // bounded retry for transient provider failures
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Invalid environment variable name: "${key}"
- Resource-limit preflight command failed.
- ${label} command failed (exit ${result.exitCode}): ${detail}
- Unable to verify path stays within workspace root: ${inputPa
- ${context} failed (exit ${result.exitCode}): ${result.stderr
AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30).
Data as JSON: /api/errors/fd50ca2aea0e0650.
Report an issue: GitHub.