mastra-ai/mastra · error

writeFile ${path} failed (exit ${result.exitCode}): ${result

Error message

writeFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}

What it means

writeFile throws this generic Error when the sandbox shell command exits with a non-zero code that is not the EXIT_EXISTS sentinel — i.e. the write failed for a reason other than 'file already exists'. The message carries the path, exit code, and stderr from the failed shell command.

Source

Thrown at mastracode/sdk/src/agents/sandbox-filesystem.ts:281

    }
    return buffer;
  }

  async writeFile(path: string, content: FileContent, options?: WriteOptions): Promise<void> {
    const abs = await this.resolveAsync(path);
    await this.assertContainedDest(abs, path);
    const b64 = toBuffer(content).toString('base64');
    const dir = posixPath.dirname(abs);
    const mkdir = options?.recursive === false ? '' : `mkdir -p ${shellQuote(dir)} && `;
    if (options?.overwrite === false) {
      // `set -C` (noclobber) makes the redirect itself the exclusivity check —
      // no exists() pre-check that could race with a concurrent writer.
      const result = await this.exec(
        `${mkdir}{ (set -C; printf %s ${shellQuote(b64)} | base64 -d > ${shellQuote(abs)}) 2>/dev/null || { [ -e ${shellQuote(abs)} ] && exit ${EXIT_EXISTS} || exit 1; }; }`,
      );
      if (result.exitCode === EXIT_EXISTS) throw new FileExistsError(path);
      if (result.exitCode !== 0) {
        throw new Error(`writeFile ${path} failed (exit ${result.exitCode}): ${result.stderr.trim()}`);
      }
      return;
    }
    await this.execOk(`${mkdir}printf %s ${shellQuote(b64)} | base64 -d > ${shellQuote(abs)}`, `writeFile ${path}`);
  }

  async appendFile(path: string, content: FileContent): Promise<void> {
    const abs = await this.resolveAsync(path);
    await this.assertContainedDest(abs, path);
    const b64 = toBuffer(content).toString('base64');
    await this.execOk(
      `mkdir -p ${shellQuote(posixPath.dirname(abs))} && printf %s ${shellQuote(b64)} | base64 -d >> ${shellQuote(abs)}`,
      `appendFile ${path}`,
    );
  }

  async deleteFile(path: string, options?: RemoveOptions): Promise<void> {
    const abs = await this.resolveAsync(path);

View on GitHub (pinned to 75dd419e61)

Solutions

  1. Read the stderr portion of the message to identify the concrete shell failure (mkdir vs base64 vs redirect).
  2. Verify the destination path is a file path, not a directory, and each parent component is a directory.
  3. Check sandbox disk space/quota (df) if the failure is 'No space left on device'.
  4. Ensure the sandbox user has write permission on the target directory, or recreate the workspace.
  5. Retry the operation — transient sandbox or volume errors can cause one-off failures.

Example fix

// before\nawait fs.writeFile('out/data.txt', buf);\n// after\ntry {\n  await fs.writeFile('out/data.txt', buf);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('Is a directory')) {\n    await fs.deleteFile('out/data.txt', { force: true });\n    await fs.writeFile('out/data.txt', buf);\n  } else throw e;\n}
Defensive patterns

Strategy: retry

Validate before calling

// Verify destination is writable and parents are directories\nconst entries = await fs.readDirectory(posix.dirname(destPath));\nif (entries.directories.every(d => d.path !== posix.basename(destPath)) === false) {\n  throw new Error('destination is a directory');\n}

Type guard

function isWriteFailureError(e: unknown): boolean {\n  return e instanceof Error && /^writeFile .* failed \\(exit/.test(e.message);\n}

Try / catch

try {\n  await fs.writeFile(path, content);\n} catch (e) {\n  if (e instanceof Error && /ENOSPC|No space left/.test(e.message)) {\n    // free space or fail fast\n  } else if (e instanceof Error && e.message.includes('failed (exit')) {\n    // log stderr from message; retry once\n  }\n  throw e;\n}

Prevention

When it happens

Trigger: writeFile where mkdir -p on the parent directory fails (permission denied or parent is a file); base64 -d failing on the pipeline; the destination being an existing directory; noclobber create failing for reasons besides existence; disk-full on the sandbox volume.

Common situations: Passing a directory as the write path; the parent path component being a regular file (e.g. writing 'a/b' where 'a' is a file); sandbox volume quota exhausted; restrictive umask/ownership after container restarts.

Related errors


AI-assisted analysis of mastra-ai/mastra@75dd419e61 (2026-08-30). Data as JSON: /api/errors/4547efc701d1c366. Report an issue: GitHub.