{"record":{"id":"b606bb93d06087c0","repo":"paperclipai/paperclip","slug":"additional-source-localpath-is-not-an-absolute-pat-b606bb","errorCode":null,"errorMessage":"additional source localPath is not an absolute path: ${localPath}","messagePattern":"additional source localPath is not an absolute path: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/adapter-utils/src/sandbox-managed-runtime.ts","lineNumber":1011,"sourceCode":"        progressBytes: assetTarSize,\n      });\n    }\n\n    // Stage each referenced (additional) project as a plain, read-only tree in\n    // its OWN isolated remote directory (`project-<projectId>`). An additional\n    // project rides one confined `syncIn` directory mapping — a native directory\n    // transfer, or the base64-tar fallback — with source and target confined to\n    // their own roots. No workspace, git-history, or `.paperclip-runtime`\n    // semantics apply; those stay anchor-only. Per-project failure isolation: one\n    // project's confinement or sync failure logs a warning and is skipped, and\n    // the run plus the other projects continue. Only a project that stages\n    // successfully appears in `additionalSourceDirs`.\n    for (const source of input.additionalSources ?? []) {\n      const { localPath, projectId } = source;\n      const label = `project-${projectId}`;\n      try {\n        if (!path.posix.isAbsolute(localPath)) {\n          throw new Error(`additional source localPath is not an absolute path: ${localPath}`);\n        }\n        if (\n          projectId.length === 0 ||\n          projectId.includes(\"/\") ||\n          projectId.includes(\"\\\\\") ||\n          projectId.includes(\"..\")\n        ) {\n          throw new Error(`additional source projectId is not a simple path segment: ${projectId}`);\n        }\n        const remoteProjectDir = path.posix.join(runtimeRootDir, label);\n        await emitRuntimeStatus(input.onRuntimeProgress, \"config_sync\", \"Syncing referenced project to sandbox\");\n        await stageConfinedSyncIn({\n          files: [{\n            sourcePath: localPath,\n            targetPath: remoteProjectDir,\n            kind: \"directory\",\n            exclude: additionalSourceExclude,\n            access: \"ro\",","sourceCodeStart":993,"sourceCodeEnd":1029,"githubUrl":"https://github.com/paperclipai/paperclip/blob/67001ec6eb96ae601aa27bc91d9b2415d665334a/packages/adapter-utils/src/sandbox-managed-runtime.ts#L993-L1029","documentation":"Thrown while iterating input.additionalSources when a source's localPath is not a POSIX-absolute path. Additional (referenced) projects ride one confined directory sync each; because the confinement logic and the sync transport require an absolute source, a relative path is rejected before any transfer is attempted. The error is per-source and caught by the surrounding try block so other projects continue.","triggerScenarios":"prepareSandboxManagedRuntime called with additionalSources containing an entry whose localPath lacks a leading slash (e.g. 'libs/shared' or './repo'). path.posix.isAbsolute returns false and this throws inside the per-project try.","commonSituations":"Caller passes a workspace-relative reference path instead of resolving it; a config field that should hold an absolute repo root was populated with a relative glob; cross-platform path handling produced a driveless path on the orchestrator.","solutions":["Resolve additionalSource.localPath with path.resolve() (or path.posix.resolve for remote-style) before passing it in.","Validate localPath at the API boundary that collects additional sources.","Confirm the source object came from a resolver that emits absolute paths, not a raw user string.","Check the per-project failure is logged as a warning (the surrounding catch skips that project) and fix the offending entry."],"exampleFix":"// before\nadditionalSources: [{ localPath: 'libs/shared', projectId: 'shared' }]\n// after\nadditionalSources: [{ localPath: path.resolve(workspaceRoot, 'libs/shared'), projectId: 'shared' }]","handlingStrategy":"validation","validationCode":"for (const s of additionalSources ?? []) {\n  if (!path.posix.isAbsolute(s.localPath)) {\n    throw new Error(`additionalSource localPath must be absolute: ${s.localPath}`);\n  }\n}","typeGuard":"function isAbsoluteLocalPath(p: string): boolean {\n  return typeof p === 'string' && path.posix.isAbsolute(p);\n}","tryCatchPattern":null,"preventionTips":["Resolve additional-source paths at the collection boundary with path.resolve.","Treat the additionalSources field as requiring absolute paths in its type.","Log skipped projects (the surrounding catch already warns) to catch regressions."],"tags":["sandbox","additional-sources","path","validation"],"backgroundTag":null,"analyzedSha":"67001ec6eb96ae601aa27bc91d9b2415d665334a","analyzedAt":"2026-08-12T12:05:45.408Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}