ruvnet/ruflo · error · Error
scoreBy='nearest' requires a probe vector
Error message
scoreBy='nearest' requires a probe vector
What it means
Thrown by the agenticow_speculate handler (agenticow-speculate-tools.ts:149) when scoring mode is 'nearest' but no probe vector was supplied. Each candidate branch is scored by querying it with the probe, so the probe is required to rank candidates in nearest mode. Critically, the handler normalizes scoreBy as `input.scoreBy === 'count' ? 'count' : 'nearest'` — 'nearest' is the DEFAULT, and anything that is not exactly the lowercase string 'count' becomes 'nearest'.
Solutions
- Add probe: a flat number[] with the same dimension as the base memory: probe: [0.12, -0.43, ...]
- Or set scoreBy to exactly 'count' (lowercase) when you want ingestion-count scoring with no probe
- Check for typos in scoreBy — anything not exactly 'count' silently selects 'nearest'
Example fix
// before
await callTool('agenticow_speculate', {
basePath: 'memory/main.rvf',
candidates: [{ label: 'a', ingest: [{ vector: v1 }] }],
// scoreBy omitted -> defaults to 'nearest' -> throws
});
// after (option A: supply probe)
await callTool('agenticow_speculate', {
basePath: 'memory/main.rvf',
candidates: [{ label: 'a', ingest: [{ vector: v1 }] }],
scoreBy: 'nearest', probe: q,
});
// after (option B: count scoring, no probe)
await callTool('agenticow_speculate', {
basePath: 'memory/main.rvf',
candidates: [{ label: 'a', ingest: [{ vector: v1 }] }],
scoreBy: 'count',
}); Defensive patterns
Strategy: validation
Validate before calling
const scoreBy = args.scoreBy === 'count' ? 'count' : 'nearest'; // mirror the tool's normalization
if (scoreBy === 'nearest') {
if (!Array.isArray(args.probe) || args.probe.length === 0) {
throw new TypeError("scoreBy='nearest' (the default) requires probe: number[]");
}
} Type guard
const isNumberArray = (v: unknown): v is number[] => Array.isArray(v) && v.every((n) => typeof n === 'number');
Try / catch
try {
await callTool('agenticow_speculate', args);
} catch (e) {
if (e instanceof Error && e.message.includes('requires a probe vector')) {
args.scoreBy = 'count'; // graceful downgrade to count scoring
return callTool('agenticow_speculate', args);
}
throw e;
} Prevention
- Set scoreBy explicitly every time — omitting it silently means 'nearest' and requires a probe
- Spell 'count' exactly (lowercase); any other value becomes 'nearest'
- Send probe as a flat number[] with the same dimension as the base memory
When it happens
Trigger: Omitting scoreBy (defaults to 'nearest') without a probe; a typo like 'Count', 'counts', or 'NEAREST'; explicitly passing scoreBy:'nearest' without probe. probe must be an actual array — a non-array value is coerced to null and fails the check even though the key is present.
Common situations: Users who only want count-based scoring forget to set scoreBy:'count' exactly; probe sent as a JSON string or nested object instead of a flat number[]; probe vector of a different length than the base dimension (passes this check but fails downstream).
Related errors
- at least one candidate is required
- candidate must ingest at least one vector
- each record requires a non-empty numeric vector
- label exceeds 256 chars
- label is required
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/92395237964775f3.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/mcp-tools/agenticow-speculate-tools.ts:149
},
required: ['basePath', 'candidates'],
},
handler: async (input) => {
const api = await loadAgenticow();
if (!api) return degradedResult('agenticow-not-found');
const basePath = resolveMemoryPath(String(input.basePath));
const dimension = input.dimension as number | undefined;
const scoreBy = (input.scoreBy as string) === 'count' ? 'count' : 'nearest';
const k = Number.isInteger(input.k) && (input.k as number) > 0 ? (input.k as number) : 1;
const probe = Array.isArray(input.probe) ? (input.probe as number[]) : null;
const rawCandidates = input.candidates as CandidateInput[];
if (!Array.isArray(rawCandidates) || rawCandidates.length === 0) {
throw new Error('at least one candidate is required');
}
if (scoreBy === 'nearest' && !probe) {
throw new Error("scoreBy='nearest' requires a probe vector");
}
// Build the generic {label, fn} candidates. Each fn ingests into its own
// branch handle, then (for 'nearest') probes it so we can score.
// Map validated label → explicit branchPath so the branchPath() resolver
// below is O(1) instead of re-scanning + re-validating rawCandidates per
// candidate (explore() calls branchPath once per candidate → was O(n²)).
const explicitBranchPaths = new Map<string, string>();
const candidates: SpeculativeCandidate<CandidateOutcome>[] = rawCandidates.map((c) => {
const label = validateLabel(String(c.label));
if (!Array.isArray(c.ingest) || c.ingest.length === 0) {
throw new Error(`candidate ${label} must ingest at least one vector`);
}
if (typeof c.branchPath === 'string' && c.branchPath) {
explicitBranchPaths.set(label, c.branchPath);
}
const records = c.ingest.map((r) => ({
...(Number.isInteger(r.id) ? { id: r.id as number } : {}),View on GitHub (pinned to fa13ee4ad6)