paperclipai/paperclip · warning
additional source localPath is not an absolute path: ${local
Error message
additional source localPath is not an absolute path: ${localPath} What it means
Thrown inside the additional-sources staging loop in remote-managed-runtime when path.posix.isAbsolute(localPath) is false. Additional sources are synced to the remote runtime via rsync-over-ssh and require a posix-absolute local path. The throw is caught per-source and logged as a warning (the source is skipped); it does not fail the whole run.
Source
Thrown at packages/adapter-utils/src/remote-managed-runtime.ts:185
baselineSnapshot,
restoreGitHistory: preparedWorkspace.gitBacked,
onProgress: input.onProgress,
});
}
throw error;
}
// Stage each referenced (additional) project as a plain, read-only tree in its
// OWN isolated remote directory (`project-<projectId>`). Additional sources
// never get the anchor's git-history/overlay semantics. Per-project failure
// isolation: one project's failure logs a warning and is skipped; the run and
// the other projects continue (no workspace restore, unlike an asset failure).
const additionalSourceDirs: Record<string, string> = {};
for (const source of input.additionalSources ?? []) {
const { localPath, projectId } = source;
try {
if (!path.posix.isAbsolute(localPath)) {
throw new Error(`additional source localPath is not an absolute path: ${localPath}`);
}
if (
projectId.length === 0 ||
projectId.includes("/") ||
projectId.includes("\\") ||
projectId.includes("..")
) {
throw new Error(`additional source projectId is not a simple path segment: ${projectId}`);
}
const remoteDir = path.posix.join(runtimeRootDir, `project-${projectId}`);
await syncDirectoryToSsh({
spec: input.spec,
localDir: localPath,
remoteDir,
exclude: REMOTE_ADDITIONAL_SOURCE_HEAVY_DIR_EXCLUDES,
onProgress: input.onProgress,
progressLabel: `project-${projectId}`,
});View on GitHub (pinned to 67001ec6eb)
Solutions
- Resolve localPath to an absolute path before constructing additionalSources: path.resolve(baseDir, source.localPath).
- Watch the warning logs ([paperclip] Failed to stage referenced project ...) — a skipped source is reported there, not as a thrown error to your caller.
- Validate at config load: assert(path.isAbsolute(source.localPath)) for every additional source.
- If you need to keep relative paths in config, resolve them at the boundary that knows the base directory before handing them to the runtime.
Example fix
// before
additionalSources: [{ localPath: "./libs/foo", projectId: "foo" }]
// after
additionalSources: [{ localPath: path.resolve(baseDir, "libs/foo"), projectId: "foo" }] Defensive patterns
Strategy: validation
Validate before calling
function normalizeAdditionalSource(source: { localPath: string; projectId: string }, baseDir: string) {
const localPath = path.isAbsolute(source.localPath) ? source.localPath : path.resolve(baseDir, source.localPath);
if (!path.isAbsolute(localPath)) {
throw new Error(`additional source localPath could not be resolved to absolute: ${source.localPath}`);
}
return { ...source, localPath };
}
const normalized = (input.additionalSources ?? []).map((s) => normalizeAdditionalSource(s, baseDir)); Type guard
function isAdditionalSource(value: unknown): value is { localPath: string; projectId: string } {
return (
typeof value === "object" && value !== null &&
typeof (value as any).localPath === "string" &&
typeof (value as any).projectId === "string"
);
} Try / catch
// Per-source failures are already caught and logged as warnings by remote-managed-runtime.
// Watch for `[paperclip] Failed to stage referenced project` in logs to catch silent skips.
for (const source of input.additionalSources ?? []) {
if (!path.isAbsolute(source.localPath)) {
console.warn(`Skipping non-absolute additional source: ${source.localPath}`);
}
} Prevention
- Resolve every additional source's localPath to absolute at the config boundary.
- Watch for the [paperclip] Failed to stage referenced project warning — it is the only signal of a skipped source.
- Validate path.isAbsolute at config load and reject early.
When it happens
Trigger: additionalSources: [{ localPath: "./libs/foo", projectId: "foo" }] or [{ localPath: "libs/foo", projectId: "foo" }] — relative paths hit the check at remote-managed-runtime.ts:184-186. The throw is wrapped in a try/catch at line 183/205 that logs `[paperclip] Failed to stage referenced project ${projectId}; skipping it.` and continues with the next source.
Common situations: Config that stores project paths relative to a base directory expecting the runtime to resolve them; user input from a CLI that did not call path.resolve; or symlinked paths whose toString is relative. The result is a missing project on the remote rather than a hard failure, which can mask itself as a downstream import error.
Related errors
- additional source projectId is not a simple path segment: ${
- Sandbox cwd "${cwd}" must be inside workspaceDir "${workspac
- Writable sandbox path "${normalizedExtraPath}" is outside sy
- Sandbox path alias "${aliasPath}" must target the synchroniz
- networkAllowlist[${index}] must be a string.
AI-assisted analysis of paperclipai/paperclip@67001ec6eb (2026-08-12).
Data as JSON: /api/errors/0825f25a82d1d272.
Report an issue: GitHub.