{"record":{"id":"75f9cf3a44618b30","repo":"ruvnet/ruflo","slug":"invalid-anchor-task-id-at-index-index","errorCode":null,"errorMessage":"invalid anchor task id at index ${index}","messagePattern":"invalid anchor task id at index (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/services/harness-project-anchor.ts","lineNumber":100,"sourceCode":"  return actual;\n}\n\nfunction parseTasks(path: string): { version: string; tasks: HumanEvalTask[] } {\n  const parsed = JSON.parse(readFileSync(path, 'utf8')) as {\n    schemaVersion?: string;\n    version?: string;\n    tasks?: HumanEvalTask[];\n  };\n  if (parsed.schemaVersion && parsed.schemaVersion !== PROJECT_ANCHOR_SCHEMA) {\n    throw new Error(`unsupported flywheel anchor schema: ${parsed.schemaVersion}`);\n  }\n  if (!Array.isArray(parsed.tasks) || parsed.tasks.length < 4) {\n    throw new Error('project flywheel anchor requires at least 4 labelled tasks');\n  }\n  const ids = new Set<string>();\n  for (const [index, task] of parsed.tasks.entries()) {\n    if (!task || typeof task.id !== 'string' || !/^[A-Za-z0-9._-]{1,128}$/.test(task.id)) {\n      throw new Error(`invalid anchor task id at index ${index}`);\n    }\n    if (ids.has(task.id)) throw new Error(`duplicate anchor task id: ${task.id}`);\n    ids.add(task.id);\n    if (typeof task.q !== 'string' || task.q.trim().length === 0) {\n      throw new Error(`anchor task ${task.id} has no query`);\n    }\n    if (!Array.isArray(task.labels) || task.labels.length === 0 || task.labels.some((label) => typeof label !== 'string' || !label.trim())) {\n      throw new Error(`anchor task ${task.id} requires non-empty string labels`);\n    }\n  }\n  return { version: parsed.version ?? 'project-anchor-v1', tasks: parsed.tasks };\n}\n\nfunction toSelection(\n  path: string,\n  expectedHash: string,\n): FlywheelAnchorSelection {\n  const parsed = parseTasks(path);","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/ruvnet/ruflo/blob/2602b642d92234c710ffbe96bfb33007d481ceab/v3/@claude-flow/cli/src/services/harness-project-anchor.ts#L82-L118","documentation":"Each anchor task's `id` must match `^[A-Za-z0-9._-]{1,128}$` — ASCII alphanumerics, dot, underscore, hyphen; at most 128 characters; no whitespace or other symbols. IDs become correlation keys in receipts and lineage records, so the format is strict; the message reports the offending array index so you can find it fast.","triggerScenarios":"Task ids containing spaces, slashes, colons (`task: 1`), unicode characters, ids longer than 128 chars, or non-string ids (bare numbers in JSON) — validation runs per task in file order.","commonSituations":"Copying ids verbatim from ticket systems ('PROJ-123 fix login'); unicode ids from localization workflows; JSON generated by scripts with numeric primary keys.","solutions":["Rewrite ids to the allowed alphabet, e.g. `proj-123-fix-login`","Truncate ids longer than 128 characters while keeping them unique","Make sure the JSON contains strings, not numbers (`\"id\": 1` becomes `\"id\": \"1\"`)"],"exampleFix":"// before\n{ \"id\": \"PROJ-123 fix/login\", \"q\": \"...\", \"labels\": [\"...\"] }\n\n// after\n{ \"id\": \"PROJ-123-fix-login\", \"q\": \"...\", \"labels\": [\"...\"] }","handlingStrategy":"type-guard","validationCode":"import { readFileSync } from 'node:fs';\n\nconst TASK_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;\n\nfunction anchorTaskIdsOk(file: string): { ok: boolean; badIndex?: number } {\n  const { tasks } = JSON.parse(readFileSync(file, 'utf8'));\n  if (!Array.isArray(tasks)) return { ok: false };\n  for (const [i, t] of tasks.entries()) {\n    if (!t || typeof t.id !== 'string' || !TASK_ID_RE.test(t.id)) return { ok: false, badIndex: i };\n  }\n  return { ok: true };\n}","typeGuard":"const TASK_ID_RE = /^[A-Za-z0-9._-]{1,128}$/;\n\ninterface TaskLike { id?: unknown; q?: unknown; labels?: unknown; }\n\nfunction hasValidTaskId(task: unknown): task is TaskLike & { id: string } {\n  return typeof (task as TaskLike)?.id === 'string' && TASK_ID_RE.test((task as TaskLike).id as string);\n}\n\n// Usage: filter/flag bad tasks before writing or sending the file\nconst invalid = tasks.map((t, i) => ({ t, i })).filter(({ t }) => !hasValidTaskId(t));","tryCatchPattern":"try {\n  return loadEffectiveFlywheelAnchor(root, opts);\n} catch (e) {\n  if (e instanceof Error && /^invalid anchor task id at index \\d+$/.test(e.message)) {\n    const index = Number(e.message.match(/(\\d+)$/)?.[1]);\n    throw new Error(`Task #${index} has an id outside [A-Za-z0-9._-]{1,128} — slugify it before retrying.`);\n  }\n  throw e;\n}","preventionTips":["Slugify ids from ticket systems at generation time (spaces and slashes are the usual culprits)","Cap ids at 128 chars","Emit ids as JSON strings, never bare numbers"],"tags":["schema","validation","anchor","id-format"],"backgroundTag":"schema-validation-failed","analyzedSha":"2602b642d92234c710ffbe96bfb33007d481ceab","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}