firecrawl/open-lovable · error · Error
Failed to write file via shell: ${normalizedPath}
Error message
Failed to write file via shell: ${normalizedPath} What it means
writeFileToSandbox falls back to shell redirection (a heredoc via bash -lc) when no provider-native write API exists, and throws this error if that shell command exits non-zero. It means the file content could not be written into the sandbox filesystem. Because the path is interpolated into the shell command, shell-hostile content (quotes, backticks, heredoc-delimiter text) can also make the write fail.
Source
Thrown at lib/morph-fast-apply.ts:162
await sandbox.files.write(fullPath, content);
} else if (sandbox?.runCode) {
// Use Python to write safely
const escaped = content
.replace(/\\/g, '\\\\')
.replace(/"""/g, '\"\"\"');
await sandbox.runCode(`
import os
os.makedirs(os.path.dirname("${fullPath}"), exist_ok=True)
with open("${fullPath}", 'w') as f:
f.write("""${escaped}""")
print("WROTE:${fullPath}")
`);
} else if (sandbox?.commands?.run) {
// Shell redirection (fallback)
// Note: beware of special chars; this is a last-resort path
const result = await sandbox.commands.run(`bash -lc 'mkdir -p "$(dirname "${fullPath}")" && cat > "${fullPath}" << \EOF\n${content}\nEOF'`, { cwd: '/home/user/app', timeout: 60 });
if (result?.exitCode !== 0) {
throw new Error(`Failed to write file via shell: ${normalizedPath}`);
}
} else {
throw new Error('No available method to write files to sandbox');
}
// Update backend cache if available
if ((global as any).sandboxState?.fileCache) {
(global as any).sandboxState.fileCache.files[normalizedPath] = {
content,
lastModified: Date.now()
};
}
if ((global as any).existingFiles) {
(global as any).existingFiles.add(normalizedPath);
}
}
export async function applyMorphEditToFile(params: {View on GitHub (pinned to 69bd93bae7)
Solutions
- Prefer a sandbox provider exposing a native writeFile API so the shell fallback never runs.
- Check the command result's stderr (log result.stdout/stderr before throwing) to see the underlying shell failure.
- Escape or strip shell-special characters in content/path, or base64-encode the content and decode on write (`echo <b64> | base64 -d > file`).
- Verify the target directory is writable in the sandbox (not read-only, correct user permissions).
- Wrap in try/catch to surface the underlying command output to the caller for diagnosis.
Example fix
// before
await sandbox.commands.run(`bash -lc 'mkdir -p "$(dirname "${fullPath}")" && cat > "${fullPath}" << \EOF\n${content}\nEOF'`, ...);
// after
const encoded = Buffer.from(content).toString('base64');
await sandbox.commands.run(`bash -lc 'mkdir -p "$(dirname "${fullPath}")" && echo ${encoded} | base64 -d > "${fullPath}"'`, { cwd: '/home/user/app', timeout: 60 }); Defensive patterns
Strategy: validation
Validate before calling
if (!/^[-\w./]+$/.test(fullPath)) {
throw new Error(`Unsafe path for shell write: ${fullPath}`);
}
if (/^(EOF|[`$"])/m.test(content) || content.includes('\\')) {
// use base64 encoding instead of heredoc
} Try / catch
try {
await writeFileToSandbox(sandbox, normalizedPath, fullPath, content);
} catch (err) {
if (err instanceof Error && err.message.startsWith('Failed to write file via shell')) {
const result = await sandbox.commands.run(`ls -ld $(dirname ${fullPath})`, { cwd: '/home/user/app' });
console.error(`Shell write failed; dir state: ${result?.stdout}, cause: ${err.message}`);
return retryWithEncodedWrite(); // base64-encoded retry
}
throw err;
} Prevention
- Base64-encode file content before shell writes to avoid quoting/heredoc breakage.
- Prefer sandbox providers with a native writeFile API; reserve shell redirection as last resort.
- Verify the target directory is writable (not read-only mount) in sandbox setup.
- Log command stdout/stderr on failure instead of only the path.
- Check sandbox disk usage for large content writes.
When it happens
Trigger: The sandbox exposes sandbox.commands.run but neither a writeFile nor another native write method, and the executed `mkdir -p ... cat > file << EOF` command fails — e.g. read-only filesystem, permissions, disk full, or content containing characters that break the heredoc/quoting (backticks, unmatched quotes, a line equal to the EOF delimiter).
Common situations: Editing files containing template literals or shell special characters; sandbox volume mounted read-only; content larger than command-length limits; running as a non-root user without write permission to the target directory.
Related errors
- Unable to read file: ${normalizedPath}
- Failed to list files
- Failed to write file via command: ${writeResult.stderr}
- Failed to read file: ${stderr}
- Unsupported sandbox type
AI-assisted analysis of firecrawl/open-lovable@69bd93bae7 (2026-08-28).
Data as JSON: /api/errors/67915d54c250b6af.
Report an issue: GitHub.