paperclipai/paperclip · error · Error
paperclip_runner_attachment_staging_size_denied
paperclip_runner_attachment_staging_size_denied
Error message
paperclip_runner_attachment_staging_size_denied
What it means
Guard in stageNativeRunnerAttachmentBytes enforcing the maximum attachment payload size (MAX_ATTACHMENT_BYTES) before any staging work begins. Oversized bodies are rejected immediately with this coded error rather than being partially staged or silently truncated.
Solutions
- Reduce the body size before staging (compress, chunk, or upload via register_deliverable/attachments API instead)
- Check MAX_ATTACHMENT_BYTES and stage a smaller file that fits the limit
- For large deliverables, register a work product or published URL rather than staging raw bytes
Example fix
// before
await stageNativeRunnerAttachmentBytes({ workspaceRoot, body: hugeBuffer })
// after
if (hugeBuffer.length > MAX_ATTACHMENT_BYTES) throw new Error("split or upload via attachments API");
await stageNativeRunnerAttachmentBytes({ workspaceRoot, body: withinLimitBuffer }) Defensive patterns
Strategy: validation
Validate before calling
if (Buffer.byteLength(body) > MAX_ATTACHMENT_BYTES) {
throw new Error(`attachment body ${body.length} exceeds MAX_ATTACHMENT_BYTES (${MAX_ATTACHMENT_BYTES}); compress or upload via attachments API`);
} Type guard
const withinAttachmentLimit = (buf, max = MAX_ATTACHMENT_BYTES) => Buffer.isBuffer(buf) && buf.length <= max;
Try / catch
try { await stageNativeRunnerAttachmentBytes({ workspaceRoot, body }); } catch (e) { if (e.message === "paperclip_runner_attachment_staging_size_denied") { /* compress/chunk or switch to register_deliverable/published URL */ } else throw e; } Prevention
- Check payload size before calling staging, not after
- Prefer publishing large artifacts (URL/work product) over staging raw bytes
- Track MAX_ATTACHMENT_BYTES changes when upgrading the server
When it happens
Trigger: Calling stageNativeRunnerAttachmentBytes with input.body.length > MAX_ATTACHMENT_BYTES, e.g. attempting to stage a multi-hundred-MB attachment into the runner workspace.
Common situations: Runner tries to hand off a huge generated artifact as an 'attachment'; caller mistakenly passes the whole file instead of a reference; configured attachment cap lowered while clients still send old large payloads.
Understand the failure class
Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.
Related errors
- github_attachment_too_large
- Attachment exceeds the configured size limit
- attachment_not_ready
- Chat SDK state exceeds the -byte limit
- Completion cites no registered attachment on this task. Use…
AI-assisted analysis of paperclipai/paperclip@3f1d897a7c (2026-09-18).
Data as JSON: /api/errors/007b7f26d4082eba.
Report an issue: GitHub.
Appendix: source
Thrown at server/src/services/native-runtime/native-runner-file-handoff.ts:746
// identifies the inode that is safe to clear.
if (safeToClear) {
await handle.truncate(0);
await handle.sync();
}
} finally {
await handle.close();
}
}
}
}
/** Stage already-authorized bytes using the same confined, scrubbed slots as wake files. */
export async function stageNativeRunnerAttachmentBytes(input: {
workspaceRoot: string;
body: Buffer;
}): Promise<{ workspaceRelativePath: string; cleanup(): Promise<void> }> {
if (input.body.length > MAX_ATTACHMENT_BYTES) {
throw new Error("paperclip_runner_attachment_staging_size_denied");
}
const workspaceRoot = await realpath(input.workspaceRoot);
const processDirectoryName = await currentStagingProcessDirectoryName();
let destination = "";
let release = () => undefined;
await withStagingRegistryLock(workspaceRoot, async () => {
const directory = await ensurePrivateStagingDirectory(
workspaceRoot,
processDirectoryName,
);
const active =
activeStagingPathsByWorkspace.get(workspaceRoot) ?? new Set<string>();
const reusable = await scrubNativeRunnerStagingResidue(
workspaceRoot,
active,
processDirectoryName,
);
destination = reusable[0] ?? path.join(directory, randomUUID());View on GitHub (pinned to 3f1d897a7c)