{"record":{"id":"48eed07abc12515a","repo":"paperclipai/paperclip","slug":"unable-to-create-a-linux-safe-paperclip-sandbox-pr","errorCode":null,"errorMessage":"Unable to create a Linux-safe Paperclip sandbox proxy socket directory.","messagePattern":"Unable to create a Linux-safe Paperclip sandbox proxy socket directory\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapter-utils/src/local-process-sandbox.ts","lineNumber":194,"sourceCode":"\nasync function createNetworkProxyTempDir(): Promise<string> {\n  const candidates = Array.from(new Set([\"/tmp\", os.tmpdir()]));\n  let lastError: unknown;\n  for (const baseDir of candidates) {\n    try {\n      const tempDir = await fs.mkdtemp(path.join(baseDir, NETWORK_PROXY_TEMP_PREFIX));\n      try {\n        assertUnixSocketPathLength(path.join(tempDir, \"proxy.sock\"));\n        return tempDir;\n      } catch (error) {\n        await fs.rm(tempDir, { recursive: true, force: true });\n        lastError = error;\n      }\n    } catch (error) {\n      lastError = error;\n    }\n  }\n  throw new Error(\"Unable to create a Linux-safe Paperclip sandbox proxy socket directory.\", { cause: lastError });\n}\n\nfunction parseTrustedNetworkUrl(value: string): NetworkAllowlistRule | null {\n  try {\n    const parsed = new URL(value);\n    if (parsed.protocol !== \"http:\" && parsed.protocol !== \"https:\") return null;\n    return {\n      hostname: parsed.hostname.toLowerCase(),\n      port: parsed.port || (parsed.protocol === \"https:\" ? \"443\" : \"80\"),\n    };\n  } catch {\n    return null;\n  }\n}\n\nfunction writeProxyError(response: http.ServerResponse, status: number, code: string, message: string): void {\n  const body = `${JSON.stringify({ error: { code, message } })}\\n`;\n  response.writeHead(status, {","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapter-utils/src/local-process-sandbox.ts#L176-L212","documentation":"Thrown by createNetworkProxyTempDir after both candidate base directories (/tmp and os.tmpdir()) fail to yield a directory whose proxy.sock path fits within 107 bytes, or when mkdtemp itself fails on both. The original failure is attached via { cause: lastError } so callers can inspect why both candidates failed.","triggerScenarios":"Both /tmp and TMPDIR are unwritable, both are mounted on paths long enough that the generated paperclip-network-sandbox-XXXXXXXX/proxy.sock path exceeds 107 bytes, or both mkdtemp calls throw (ENOSPC, EROFS, EACCES). The function tries /tmp first then os.tmpdir(); only when both fail (or both produce oversized paths) does this throw.","commonSituations":"Hardened containers where /tmp is read-only or tmpfs-size-limited, CI runners where TMPDIR is set to a long path AND /tmp is overridden to the same long path, or sandbox environments where the process has no write access to either candidate. The cause field typically holds EACCES, ENOSPC, or a sibling assertUnixSocketPathLength error.","solutions":["Inspect err.cause — it tells you whether both candidates hit a length limit, a permission error, or disk-full.","Set TMPDIR to a short writable path that is NOT the same as the failing /tmp candidate: export TMPDIR=/var/tmp or a dedicated /run/paperclip owned by the runner user.","Ensure the runner user has write + create permissions on /tmp (mode 1777) and on the configured TMPDIR.","Free inodes/disk on the tmpfs backing /tmp (df -h /tmp; df -i /tmp) — mkdtemp fails with ENOSPC when either is exhausted."],"exampleFix":"// before: both /tmp and TMPDIR unusable\n// err.cause === EACCES on /tmp, EACCES on /var/run/user/1000/long/...\n\n// after: dedicated short, writable dir\nawait fs.mkdir(\"/run/paperclip\", { recursive: true, mode: 0o700 });\nprocess.env.TMPDIR = \"/run/paperclip\";\nconst target = await buildLocalProcessSandboxSpawnTarget(input);","handlingStrategy":"try-catch","validationCode":"async function preflightTempDirs(): Promise<void> {\n  const candidates = Array.from(new Set([\"/tmp\", process.env.TMPDIR ?? \"/tmp\"]));\n  for (const base of candidates) {\n    try {\n      const probe = await fs.mkdtemp(path.join(base, \"paperclip-preflight-\"));\n      const sock = path.join(probe, \"proxy.sock\");\n      if (Buffer.byteLength(sock) > 107) throw new Error(`socket path too long under ${base}`);\n      await fs.rm(probe, { recursive: true, force: true });\n      return; // at least one candidate works\n    } catch (error) {\n      // try next\n    }\n  }\n  throw new Error(\"No usable temp dir for sandbox; set TMPDIR to a short, writable path.\");\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await buildLocalProcessSandboxSpawnTarget(input);\n} catch (error) {\n  if (error instanceof Error && error.message.startsWith(\"Unable to create a Linux-safe\")) {\n    const cause = (error as Error & { cause?: unknown }).cause;\n    throw new ConfigError(`Sandbox temp dir unavailable. Cause: ${String(cause)}`, { cause: error });\n  }\n  throw error;\n}","preventionTips":["Ensure both /tmp and TMPDIR are writable by the runner user (mode 1777 or owned).","Pin TMPDIR to a short, dedicated path like /run/paperclip.","Monitor free inodes and disk on tmpfs (df -h -i /tmp); mkdtemp fails on exhaustion."],"tags":["linux","sandbox","filesystem","environment","unix-socket"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}