ruvnet/ruflo · error · Error
unsupported flywheel anchor schema: ${parsed.schemaVersion}
Error message
unsupported flywheel anchor schema: ${parsed.schemaVersion} What it means
Thrown by parseTasks() in harness-project-anchor.ts when a project-local flywheel anchor JSON file declares a schemaVersion that is not 'ruflo.flywheel-anchor/v1' (the value of PROJECT_ANCHOR_SCHEMA). The schemaVersion field is optional, but when present it must match exactly; this guards against silently consuming an anchor written for a future or incompatible schema. Ruflo pins anchors per-repository so foreign projects are evaluated against their own labelled tasks, not Ruflo's built-in benchmark.
Source
Thrown at v3/@claude-flow/cli/src/services/harness-project-anchor.ts:81
if (lexical === '..' || lexical.startsWith(`..${sep}`) || isAbsolute(lexical)) {
throw new Error('flywheel anchor path must stay inside project root');
}
const actual = realpathSync(absolute);
const physical = relative(root, actual);
if (physical === '..' || physical.startsWith(`..${sep}`) || isAbsolute(physical)) {
throw new Error('flywheel anchor symlink escapes project root');
}
return actual;
}
function parseTasks(path: string): { version: string; tasks: HumanEvalTask[] } {
const parsed = JSON.parse(readFileSync(path, 'utf8')) as {
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`);
}
}View on GitHub (pinned to 6b01dc5a68)
Solutions
- Set schemaVersion to exactly "ruflo.flywheel-anchor/v1" in the anchor JSON, or delete the field entirely (it is optional).
- Re-generate the anchor file with the project's official scaffolding/CLI command so the schema constant is written verbatim.
- If you intentionally authored a v2-format anchor, downgrade the payload to the v1 shape until the library supports it.
Example fix
// before (anchor.json)
{ "schemaVersion": "ruflo.flywheel-anchor/v2", "tasks": [...] }
// after
{ "schemaVersion": "ruflo.flywheel-anchor/v1", "tasks": [...] }
// or simply omit the field
{ "version": "project-anchor-v1", "tasks": [...] } Defensive patterns
Strategy: validation
Validate before calling
import { PROJECT_ANCHOR_SCHEMA } from './harness-project-anchor.js';
import { readFileSync } from 'fs';
function assertAnchorSchema(path: string): void {
const parsed = JSON.parse(readFileSync(path, 'utf8'));
if (parsed.schemaVersion !== undefined && parsed.schemaVersion !== PROJECT_ANCHOR_SCHEMA) {
throw new Error(`anchor schema ${parsed.schemaVersion} != ${PROJECT_ANCHOR_SCHEMA}; fix or remove the field`);
}
} Type guard
function hasValidAnchorSchema(parsed: unknown): boolean {
if (typeof parsed !== 'object' || parsed === null) return false;
const sv = (parsed as { schemaVersion?: unknown }).schemaVersion;
return sv === undefined || sv === 'ruflo.flywheel-anchor/v1';
} Try / catch
try {
loadEffectiveFlywheelAnchor(root, { anchorPath, anchorHash });
} catch (e) {
if (e instanceof Error && /unsupported flywheel anchor schema/.test(e.message)) {
// fix the schemaVersion field, then retry
}
throw e;
} Prevention
- Generate anchor files with the official scaffolding so PROJECT_ANCHOR_SCHEMA is written verbatim.
- Treat schemaVersion as opaque — never hand-type it.
- Add a JSON-schema assertion in CI that validates anchor files before commit.
When it happens
Trigger: Loading an anchor file via loadEffectiveFlywheelAnchor() (either through an explicit anchorPath, or indirectly via the .claude/eval/flywheel-anchor.manifest.json) where the JSON contains a schemaVersion like 'ruflo.flywheel-anchor/v2', 'v1', or any typo. The field is optional, so a JSON without schemaVersion passes this check.
Common situations: Hand-editing an anchor file and mistyping the schema string; upgrading claude-flow/ruflo to a version whose schema constant changed while keeping an old anchor file that used a custom/placeholder value; copying an anchor template from documentation that used a non-literal placeholder; AI-generated anchor files inventing a plausible-looking schemaVersion.
Related errors
- unsupported flywheel anchor manifest schema: ${manifest.sche
- project flywheel anchor requires at least 4 labelled tasks
- anchor task ${task.id} has no query
- flywheel anchor manifest requires path and sha256
- invalid anchor task id at index ${index}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/e9e2473168a1888a.
Report an issue: GitHub.