paperclipai/paperclip · error
CreateOS workspace preparation failed; the image must…
Error message
CreateOS workspace preparation failed; the image must provide Bash.
What it means
During acquire(), the plugin prepares the sandbox workspace by running `/bin/bash -lc 'mkdir -p <CWD>'` via the sandbox exec endpoint. If the sandbox reports a non-zero exit_code, the image is missing a working Bash (or failed to create the workspace directory), so the plugin aborts lease acquisition with this error.
Solutions
- Build the sandbox image with bash installed (e.g. `apk add bash` on alpine or use a bash-including base image).
- Verify inside the image that `/bin/bash` exists and runs: docker run --rm <image> /bin/bash -lc 'echo ok'.
- Check the workspace directory path (CWD) is creatable and the root filesystem is writable.
- Inspect the exec endpoint's full result/stderr for the underlying failure if bash exists but exits non-zero.
Example fix
// Dockerfile before (alpine, no bash) FROM alpine:3.19 // after FROM alpine:3.19 RUN apk add --no-cache bash
Defensive patterns
Strategy: validation
Validate before calling
// verify the image before acquisition await execInImage(image, "/bin/bash", ["-lc", "echo ok"]); // must exit 0
Try / catch
try {
lease = await acquire(params);
} catch (err) {
if (err.message.includes("must provide Bash")) {
// rebuild/select an image with bash installed, then retry
} else throw err;
} Prevention
- Install bash in every sandbox image (apk add bash / apt-get install bash)
- Smoke-test images with /bin/bash -lc 'echo ok' in CI
- Avoid distroless/scratch bases for sandbox images
- Keep root filesystem writable for workspace creation
When it happens
Trigger: POST /sandboxes/{id}/exec with cmd /bin/bash returns result.exit_code !== 0 — the image lacks /bin/bash, bash fails to start (missing libs), or mkdir -p fails due to permissions or a read-only root filesystem.
Common situations: Using a minimal distro image (alpine without bash, distroless, scratch); a broken image build where bash is removed; sandbox root filesystem mounted read-only; image misconfiguration after a base-image upgrade.
Related errors
- A sandbox command is required.
- [adapter-ui-loader] Failed to load UI parser for
- Bridge envelope exceeded the configured size limit.
- Bridge envelope too large
- Bridge host response body capacity is busy.
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/e2b3321e75ce7f4c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/plugins/sandbox-providers/createos/src/plugin.ts:34
function metadataMatches(params: PluginEnvironmentDriverBaseParams, metadata?: Record<string, unknown>): boolean {
return metadata?.provider === "createos" && metadata.companyId === params.companyId &&
metadata.environmentId === params.environmentId && metadata.apiUrl === parseConfig(params.config).apiUrl;
}
async function acquire(params: PluginEnvironmentAcquireLeaseParams): Promise<PluginEnvironmentLease> {
// An idle timeout or a host-local timer cannot supply a provider expiry.
if (params.requestedExpiresAt) throw new Error("CreateOS does not yet support leases with a guaranteed expiration deadline.");
const config = parseConfig(params.config);
const client = new CreateosClient(config);
const signal = AbortSignal.timeout(config.timeoutMs);
const sandbox = await client.createSandbox(signal);
try {
await client.transition(sandbox.id, "running", signal);
const data = await client.json(`/sandboxes/${sandbox.id}/exec`, "POST", {
cmd: "/bin/bash", args: ["-lc", `mkdir -p -- ${shellQuote(CWD)}`],
}, signal);
if (object(data.result).exit_code !== 0) throw new Error("CreateOS workspace preparation failed; the image must provide Bash.");
const marker = randomUUID();
await client.upload(sandbox.id, MARKER, marker, signal);
return {
providerLeaseId: sandbox.id,
metadata: {
provider: "createos", apiUrl: config.apiUrl,
companyId: params.companyId, environmentId: params.environmentId,
remoteCwd: CWD, shellCommand: "bash", marker,
shape: config.shape, rootfs: config.rootfs, region: config.region,
reuseLease: config.reuseLease,
},
};
} catch (error) {
try { await client.destroySandbox(sandbox.id); }
catch { throw new Error(`CreateOS setup failed and cleanup is unconfirmed for sandbox ${sandbox.id}.`); }
throw error;
}
}View on GitHub (pinned to 3f1d897a7c)