paperclipai/paperclip · error · Error
Invalid GitHub launcher run ID
Error message
Invalid GitHub launcher run ID
What it means
githubOperationLauncherDirectory builds the filesystem path for a managed GitHub operation launcher directory but only permits controller-generated run IDs, enforced by the regex /^[a-zA-Z0-9_-]+$/. This guard prevents arbitrary strings (potentially from untrusted run identifiers) from escaping into path construction. An ID containing slashes, dots, spaces, or other characters triggers this error.
Source
Thrown at packages/adapter-utils/src/execution-target.ts:1529
restoreWorkspace: prepared.restoreWorkspace,
};
}
export function runtimeAssetDir(
prepared: Pick<PreparedAdapterExecutionTargetRuntime, "assetDirs">,
key: string,
fallbackRemoteCwd: string,
): string {
return prepared.assetDirs[key] ?? path.posix.join(fallbackRemoteCwd, ".paperclip-runtime", key);
}
type GitHubLauncherLocation = {
runId: string; target: AdapterExecutionTarget | null | undefined;
};
function githubOperationLauncherDirectory(input: GitHubLauncherLocation): string {
// Only controller-generated run IDs may name a removable directory.
if (!/^[a-zA-Z0-9_-]+$/.test(input.runId)) throw new Error("Invalid GitHub launcher run ID");
return input.target?.kind === "remote"
? path.posix.join(input.target.remoteCwd, ".paperclip-runtime", "github", input.runId)
: path.join(os.tmpdir(), "paperclip-github-runtime", input.runId);
}
/** Call only after execution settles, before releasing its remote environment lease. */
export async function cleanupGitHubOperationLaunchers(input: GitHubLauncherLocation): Promise<void> {
const directory = githubOperationLauncherDirectory(input);
if (input.target?.kind === "remote") {
const result = await adapterExecutionTargetCommandRunner(input.target).execute({
command: "sh", args: ["-c", `rm -rf -- ${shellQuote(directory)}`],
cwd: input.target.remoteCwd, timeoutMs: 5_000,
});
if (result.exitCode !== 0) throw new Error("Could not clean managed GitHub launchers");
} else {
await fs.rm(directory, { recursive: true, force: true });
}
}View on GitHub (pinned to 01ad858492)
Solutions
- Pass only the controller-generated run ID matching [a-zA-Z0-9_-]+
- Sanitize/normalize the identifier upstream, e.g. runId.replace(/[^a-zA-Z0-9_-]/g, '')
- Verify the value is not a URL or path fragment — extract the bare ID first
Example fix
// before
cleanup({ runId: githubRun.url.split('/').pop() + '/artifacts' })
// after
const runId = githubRun.id.toString();
if (!/^[a-zA-Z0-9_-]+$/.test(runId)) throw new Error('bad run id');
cleanup({ runId, target }); Defensive patterns
Strategy: type-guard
Validate before calling
if (!/^[a-zA-Z0-9_-]+$/.test(runId)) {
throw new Error(`runId must match [a-zA-Z0-9_-]+, got: ${runId}`);
} Type guard
function isSafeRunId(v: unknown): v is string {
return typeof v === 'string' && /^[a-zA-Z0-9_-]+$/.test(v);
} Try / catch
try {
cleanupLauncher({ runId, target });
} catch (e) {
if (String(e.message) === 'Invalid GitHub launcher run ID') {
console.error('sanitize the run ID before calling cleanup');
} else throw e;
} Prevention
- Only pass controller-generated run IDs, never URLs or composite identifiers
- Sanitize external IDs at ingestion: id.replace(/[^a-zA-Z0-9_-]/g, '')
- Add a unit test asserting launcher directory calls reject unsafe IDs
When it happens
Trigger: Calling the launcher directory/cleanup API with a runId containing '/', '..', whitespace, unicode, or any character outside [a-zA-Z0-9_-]; passing a raw external identifier (e.g. a full GitHub run URL or numeric id with prefix) as runId.
Common situations: Downstream code concatenating identifiers like 'runs/12345' or 'run.id' instead of the sanitized controller run ID; test code passing placeholder IDs with slashes.
Understand the failure class
Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.
Related errors
- sandbox runtime asset key is not a simple path segment: ${ke
- codex auth cache: account_id is not a valid account handle
- Unexpected trusted viewer asset
- Public attempt must contain the read-only public chat projec
- Public replay contains private provider metadata
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/16244b1bf8aa7dde.
Report an issue: GitHub.