{"record":{"id":"daf36c1ee867534c","repo":"paperclipai/paperclip","slug":"acpx-runtime-executable-must-be-a-bounded-executab","errorCode":null,"errorMessage":"ACPX runtime executable must be a bounded executable file","messagePattern":"ACPX runtime executable must be a bounded executable file","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/paperclip-runner/src/drivers/acpx/private-snapshot.ts","lineNumber":189,"sourceCode":"      }\n    }\n    for (const root of roots)\n      for (const pkg of packages) {\n        const target = join(root, \"node_modules\", pkg.name);\n        await mkdir(dirname(target), { recursive: true, mode: 0o700 });\n        // Include generated directories in cleanup and read-only sealing.\n        directories.push(join(root, \"node_modules\"), dirname(target));\n        await symlink(pkg.root, target).catch(\n          (error: NodeJS.ErrnoException) => {\n            if (error.code !== \"EEXIST\") throw error;\n          },\n        );\n      }\n    let executablePath: string | null = null;\n    if (executable) {\n      const before = await executable.stat({ bigint: true });\n      if (!before.isFile() || before.size < 1n || before.size > BigInt(MAX_ACPX_RUNTIME_EXECUTABLE_BYTES)) {\n        throw new Error(\"ACPX runtime executable must be a bounded executable file\");\n      }\n      // The bigint bound above makes this conversion exact before allocation.\n      const executableBytes = Number(before.size);\n      bytesCopied += executableBytes;\n      if (bytesCopied > MAX_SNAPSHOT_BYTES) {\n        throw new Error(\"ACPX snapshot exceeds its byte bound\");\n      }\n      const bytes = await readSnapshotBytes(executable, executableBytes);\n      if (!same(before, await executable.stat({ bigint: true })))\n        throw new Error(\"ACPX executable changed during snapshot\");\n      executablePath = join(directory, \"runtime\");\n      await writeFile(executablePath, bytes, { flag: \"wx\", mode: 0o500 });\n      digests[executablePath] = digest(bytes);\n    }\n    const manifest = Buffer.from(\n      JSON.stringify({ roots, executable: executablePath, digests }),\n    );\n    const manifestPath = join(directory, \"manifest.json\");","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/paperclipai/paperclip/blob/01ad8584922b5d85292b1723cae71fa0d9b07a19/packages/paperclip-runner/src/drivers/acpx/private-snapshot.ts#L171-L207","documentation":"When snapshotting the ACPX runtime executable itself, createAcpxPrivateSnapshot requires the file handle's stat to show a regular file with size between 1 byte and MAX_ACPX_RUNTIME_EXECUTABLE_BYTES. Otherwise it throws this error, refusing to bundle an empty, non-regular, or oversized runtime binary into the private snapshot.","triggerScenarios":"createAcpxPrivateSnapshot is called with an `executable` whose stat({bigint:true}) reports isFile() === false, size === 0n, or size > MAX_ACPX_RUNTIME_EXECUTABLE_BYTES — i.e. the resolved ACPX runtime binary is missing content, a special file, or abnormally large.","commonSituations":"Misconfigured executable path pointing at a wrapper/stub or empty placeholder; a partially downloaded or truncated runtime binary; a custom runtime build that ballooned past the configured byte limit; pointing at a directory or device node by mistake.","solutions":["Verify the executable path resolves to the real, fully-built runtime binary (check file size is nonzero and plausible)","Reinstall/rebuild the ACPX runtime if the binary is truncated or empty","If you ship a legitimately larger runtime, adjust MAX_ACPX_RUNTIME_EXECUTABLE_BYTES in the runner configuration consciously","Ensure the path points at a regular file, not a script wrapper that is a symlink chain, fifo, or directory"],"exampleFix":"// before: placeholder stub\nexecutablePath: './bin/acpx-stub' // 0 bytes\n// after: real built binary\nexecutablePath: './dist/bin/acpx' // regular file within bound","handlingStrategy":"validation","validationCode":"const st = await fs.stat(executablePath);\nif (!st.isFile() || st.size < 1 || st.size > MAX_ACPX_RUNTIME_EXECUTABLE_BYTES) {\n  throw new Error(`invalid runtime executable at ${executablePath}: size=${st.size}`);\n}","typeGuard":"function isValidRuntimeExecutable(st: { isFile(): boolean; size: number }): boolean {\n  return st.isFile() && st.size >= 1 && st.size <= MAX_ACPX_RUNTIME_EXECUTABLE_BYTES;\n}","tryCatchPattern":"try {\n  await createAcpxPrivateSnapshot({ roots, executable });\n} catch (e) {\n  if (e.message.includes('runtime executable must be a bounded executable file')) {\n    throw new Error(`Rebuild or reconfigure the ACPX runtime at ${executable.path}; it is empty, special, or oversized`);\n  }\n  throw e;\n}","preventionTips":["Validate the runtime binary exists, is nonzero, and within the size bound at startup","Reinstall the runtime after partial downloads or failed builds","Keep wrapper scripts distinct from the binary; point configuration at the regular-file binary"],"tags":["filesystem","limit","configuration","snapshot"],"backgroundTag":"file-size-limit-exceeded","analyzedSha":"01ad8584922b5d85292b1723cae71fa0d9b07a19","analyzedAt":"2026-09-10T03:14:50.855Z","contentChangedAt":"2026-09-10T03:14:50.855Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}