ruvnet/ruflo · error

anchor task has no query

Error message

anchor task ${task.id} has no query

What it means

Every anchor task must carry a non-empty `q` — the query string, trimmed before the check. The query is the input the flywheel evaluates retrieval against; a missing or blank query makes the task meaningless and would silently skew the human-relevance delta.

Solutions

  1. Write a real query string for the task named in the message
  2. If your generator emits a different field name, map it to `q` when producing the anchor JSON
  3. Trim and assert non-empty queries in the generator so bad rows never reach the file

Example fix

// before
{ "id": "t1", "q": " ", "labels": ["api"] }

// after
{ "id": "t1", "q": "Where is the retry policy implemented?", "labels": ["src/retry.ts"] }
Defensive patterns

Strategy: type-guard

Validate before calling

function queriesFilled(tasks: Array<{ id: string; q?: unknown }>): string[] {
  return tasks
    .filter((t) => typeof t.q !== 'string' || t.q.trim().length === 0)
    .map((t) => t.id);
}

Type guard

interface TaskLike { id?: unknown; q?: unknown; labels?: unknown; }

function hasQuery(task: unknown): task is TaskLike & { q: string } {
  return typeof (task as TaskLike)?.q === 'string' && ((task as TaskLike).q as string).trim().length > 0;
}

// Usage: const missing = tasks.filter((t) => !hasQuery(t)).map((t) => t.id);

Try / catch

try {
  return loadEffectiveFlywheelAnchor(root, opts);
} catch (e) {
  if (e instanceof Error && /anchor task .+ has no query$/.test(e.message)) {
    const id = e.message.match(/anchor task (.+) has no query/)?.[1];
    throw new Error(`Task '${id}' has an empty query — fill in a real retrieval question.`);
  }
  throw e;
}

Prevention

When it happens

Trigger: A task with `q: ""`, `q: " "`, no `q` key at all, or a non-string q; validation names the offending task id.

Common situations: Template tasks never filled in; whitespace-only strings from spreadsheet/CSV exports; generators using a different field name (`query` or `prompt`) than `q`.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@2602b642d9 (2026-08-18). Data as JSON: /api/errors/80c663ef71d995e3. Report an issue: GitHub.

Appendix: source

Thrown at v3/@claude-flow/cli/src/services/harness-project-anchor.ts:105

    schemaVersion?: string;
    version?: string;
    tasks?: HumanEvalTask[];
  };
  if (parsed.schemaVersion && parsed.schemaVersion !== PROJECT_ANCHOR_SCHEMA) {
    throw new Error(`unsupported flywheel anchor schema: ${parsed.schemaVersion}`);
  }
  if (!Array.isArray(parsed.tasks) || parsed.tasks.length < 4) {
    throw new Error('project flywheel anchor requires at least 4 labelled tasks');
  }
  const ids = new Set<string>();
  for (const [index, task] of parsed.tasks.entries()) {
    if (!task || typeof task.id !== 'string' || !/^[A-Za-z0-9._-]{1,128}$/.test(task.id)) {
      throw new Error(`invalid anchor task id at index ${index}`);
    }
    if (ids.has(task.id)) throw new Error(`duplicate anchor task id: ${task.id}`);
    ids.add(task.id);
    if (typeof task.q !== 'string' || task.q.trim().length === 0) {
      throw new Error(`anchor task ${task.id} has no query`);
    }
    if (!Array.isArray(task.labels) || task.labels.length === 0 || task.labels.some((label) => typeof label !== 'string' || !label.trim())) {
      throw new Error(`anchor task ${task.id} requires non-empty string labels`);
    }
  }
  return { version: parsed.version ?? 'project-anchor-v1', tasks: parsed.tasks };
}

function toSelection(
  path: string,
  expectedHash: string,
): FlywheelAnchorSelection {
  const parsed = parseTasks(path);
  const actualHash = humanEvalHash(parsed.tasks);
  if (actualHash !== normalizeHash(expectedHash)) {
    throw new Error(`project flywheel anchor hash mismatch (got ${actualHash}, pinned ${normalizeHash(expectedHash)})`);
  }
  return {

View on GitHub (pinned to 2602b642d9)