stablyai/orca · error
Invalid external automation job ID.
Error message
Invalid external automation job ID.
What it means
Thrown by listExternalAutomationRuns() when input.jobId fails EXTERNAL_JOB_ID_PATTERN (`/^[A-Za-z0-9][A-Za-z0-9._:-]*$/`). The job ID must start alphanumeric and contain only alphanumerics, dot, underscore, colon, or hyphen. This validates the ID before it is sent to a local Hermes process or relayed over an SSH multiplexer, rejecting malformed/illegal input early.
Source
Thrown at src/main/automations/external-manager.ts:326
.getSshTargets()
// Why: runtime-owned hidden targets are excluded from SSH/run-target
// surfaces; don't probe them for external automations either.
.filter((target) => !isRuntimeOwnedSshTarget(target))
.flatMap((target) => [listRemoteHermesManager(target), listRemoteOpenClawManager(target)])
)
])
return [
...(localHermes ? [localHermes] : []),
...(localOpenClaw ? [localOpenClaw] : []),
...remote
]
}
export async function listExternalAutomationRuns(
input: ExternalAutomationRunsInput
): Promise<ExternalAutomationRunsPage> {
if (!EXTERNAL_JOB_ID_PATTERN.test(input.jobId)) {
throw new Error('Invalid external automation job ID.')
}
const page = Number.isFinite(input.page) ? Math.max(1, Math.floor(input.page)) : 1
const pageSize = Number.isFinite(input.pageSize)
? Math.min(100, Math.max(1, Math.floor(input.pageSize)))
: 25
if (input.provider !== 'hermes') {
return {
managerId: input.managerId,
provider: input.provider,
target: input.target,
jobId: input.jobId,
page,
pageSize,
total: 0,
runs: []
}
}
if (input.target.type === 'local') {View on GitHub (pinned to 1136503c6a)
Solutions
- Sanitize/validate the jobId with EXTERNAL_JOB_ID_PATTERN before calling listExternalAutomationRuns.
- Strip whitespace and any path/URL prefix to extract the bare ID.
- If the ID genuinely needs other characters, change the upstream producer to emit IDs matching the pattern.
Example fix
// before
listExternalAutomationRuns({ jobId: ' repo/job #1', ... }) // leading space + slash -> throws
// after
const jobId = (raw.trim().match(/^[A-Za-z0-9][A-Za-z0-9._:-]*/) ?? [])[0]
if (!jobId) throw new UserError('Invalid job ID')
listExternalAutomationRuns({ jobId, ... }) Defensive patterns
Strategy: validation
Validate before calling
const EXTERNAL_JOB_ID_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/
function sanitizeJobId(raw: string): string | null {
const trimmed = raw.trim()
const match = trimmed.match(EXTERNAL_JOB_ID_PATTERN)
return match ? match[0] : null
}
const jobId = sanitizeJobId(raw)
if (!jobId) throw new UserError('Job ID must start with a letter or digit and contain only A-Z a-z 0-9 . _ : -')
listExternalAutomationRuns({ jobId, ... }) Type guard
function isExternalJobId(v: unknown): v is string {
return typeof v === 'string' && /^[A-Za-z0-9][A-Za-z0-9._:-]*$/.test(v)
} Try / catch
try {
await listExternalAutomationRuns(input)
} catch (e) {
if ((e as Error).message === 'Invalid external automation job ID.') {
throw new UserError('That job ID is not valid. Use only letters, digits, . _ : - and start with a letter or digit.')
}
throw e
} Prevention
- Validate job IDs at the UI input boundary with the same regex before forwarding to the manager.
- Never pass URLs, paths, or `repo#id` tokens as jobId — extract the bare ID first.
- Trim and reject empty strings explicitly so they do not reach the manager.
When it happens
Trigger: Passing a jobId with a leading symbol, whitespace, slashes, or any char outside the allowed set; passing an empty string; passing a URL or path-like value instead of a bare job ID.
Common situations: UI forwards a user-typed string with spaces or slashes; a script passes a full URL or `repo#job` token; an injection attempt containing shell metacharacters; copy-paste includes surrounding quotes.
Related errors
- Hermes cron requires a prompt.
- Hermes cron requires a schedule.
- Only Hermes cron creation and editing are supported.
- Invalid worktree name
- Package version is not valid semver: ${baseVersion}
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/5aa9b1a94dbd270c.
Report an issue: GitHub.