{"record":{"id":"50131f1f2739f67c","repo":"can1357/oh-my-pi","slug":"invalid-job-name-jobname","errorCode":null,"errorMessage":"invalid job name: ${jobName}","messagePattern":"invalid job name: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/metaharness/src/server.ts","lineNumber":96,"sourceCode":"\tcontroller: ReadableStreamDefaultController<Uint8Array>;\n\tstate: SseState;\n}\n\nfunction parseServerArgs(argv: string[]): { port: number; jobsDir: string } {\n\tlet port = 4700;\n\tlet jobsDir = DEFAULT_JOBS_DIR;\n\tfor (let i = 0; i < argv.length; i++) {\n\t\tif (argv[i] === \"--port\" && argv[i + 1]) port = Number(argv[++i]);\n\t\telse if (argv[i] === \"--jobs-dir\" && argv[i + 1]) jobsDir = path.resolve(argv[++i]);\n\t}\n\tif (!Number.isSafeInteger(port) || port < 1 || port > 65535) throw new Error(\"--port must be 1..65535\");\n\treturn { port, jobsDir };\n}\n\n/** Job names are single path segments; anything else could escape the jobs dir. */\nfunction assertSafeJobName(jobName: string): void {\n\tif (!jobName || jobName === \".\" || jobName === \"..\" || /[/\\\\]/.test(jobName)) {\n\t\tthrow new Error(`invalid job name: ${jobName}`);\n\t}\n}\n\n/** True when `pid` names a live process (signal-0 probe). */\nfunction pidAlive(pid: number | null): boolean {\n\tif (pid == null) return false;\n\ttry {\n\t\tprocess.kill(pid, 0);\n\t\treturn true;\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Resolve the launch request for a new arm added to an existing experiment.\n * Inherits the experiment's benchmark, dataset, and — crucially — the exact\n * task sample from a sibling arm (its recorded `include`, else its observed","sourceCodeStart":78,"sourceCodeEnd":114,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/metaharness/src/server.ts#L78-L114","documentation":"Job names are used as path segments under the jobs directory, so the server rejects any name that is empty, '.', '..', or contains a path separator (/ or \\). This is a path-traversal guard: it throws before a job name is ever used in a filesystem operation such as destroying a run (#destroyRun).","triggerScenarios":"An HTTP request to the destroy-run endpoint (or any caller of #destroyRun) supplies a jobName that is empty, '.', '..', or contains a slash/backslash, causing assertSafeJobName to throw.","commonSituations":"Client-side bug embedding a full path like 'jobs/my-run' instead of just 'my-run'; URL-encoded slashes arriving in a request param; empty job id from a stale UI reference; deliberate path-traversal attempt.","solutions":["Send only the bare job name (single path segment), e.g. 'my-run-2026-08-31', not a path","Trim/validate the job name on the client before calling the destroy endpoint","URL-encode the job name correctly in requests; inspect the actual value received","Fix the caller that derives job names from file paths to strip directory components"],"exampleFix":"// before (client)\nawait fetch(`/destroy?job=${encodeURIComponent(fullPath)}`); // 'runs/_bench/job1' -> rejected\n\n// after (client)\nconst jobName = path.basename(fullPath);\nawait fetch(`/destroy?job=${encodeURIComponent(jobName)}`); // 'job1'","handlingStrategy":"validation","validationCode":"function assertSafeJobName(jobName) {\n  if (!jobName || jobName === \".\" || jobName === \"..\" || /[/\\\\]/.test(jobName)) {\n    throw new Error(`invalid job name: ${jobName}`);\n  }\n}\n// call client-side before requesting destroy: assertSafeJobName(jobName)","typeGuard":"function isSafeJobName(v) {\n  return typeof v === \"string\" && v.length > 0 && v !== \".\" && v !== \"..\" && !/[/\\\\]/.test(v);\n}","tryCatchPattern":"try {\n  await destroyRun(jobName);\n} catch (err) {\n  if (err instanceof Error && err.message.startsWith(\"invalid job name:\")) {\n    console.error(`Refusing to destroy: '${jobName}' is not a single path segment`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Always send the bare job name, never a path — apply path.basename() on the client","Validate job names with the same single-segment rule before any API call","Avoid deriving job names from user-supplied strings or URL fragments without sanitization","Restrict job-name generation to a known-safe charset (alphanumerics, dashes)"],"tags":["validation","path-traversal","input-sanitization","server-api"],"backgroundTag":"invalid-path-segment","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}