ruvnet/ruflo · error · Error
candidate ${label} must ingest at least one vector
Error message
candidate ${label} must ingest at least one vector What it means
Thrown while building the candidate list for agenticow_speculate. Every candidate must carry a non-empty `ingest` array because each branch is populated solely by ingesting those vectors — an empty branch has nothing to score or promote. The message includes the validated label so the offending candidate is identifiable.
Source
Thrown at v3/@claude-flow/cli/src/mcp-tools/agenticow-speculate-tools.ts:161
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 } : {}),
vector: r.vector,
...(typeof r.text === 'string' ? { text: r.text } : {}),
}));
return {
label,
fn: (branch: any): CandidateOutcome => {
const res = branch.ingest(records);
const accepted = Number(res?.accepted ?? records.length);
let hits: Array<{ id: number; distance: number }> = [];
if (probe) {
hits = (branch.query(probe, k) || []).map((h: any) => ({
id: h.id,View on GitHub (pinned to 6b01dc5a68)
Solutions
- Ensure every candidate includes ingest: [{ vector: [...] }] with at least one vector record.
- If a candidate legitimately has no data, drop it from the candidates array rather than passing an empty ingest.
- Validate the candidates array shape before calling the tool (see defense validationCode).
- Check that serialisation did not collapse ingest into an object or string.
Example fix
// before
{ label: 'branch-a', ingest: [] }
// after
{ label: 'branch-a', ingest: [{ vector: embedding }] } Defensive patterns
Strategy: validation
Validate before calling
function validateCandidates(candidates) {
if (!Array.isArray(candidates) || candidates.length === 0) {
throw new Error('at least one candidate required');
}
for (const c of candidates) {
if (!Array.isArray(c.ingest) || c.ingest.length === 0) {
throw new Error(`candidate ${c.label} must ingest at least one vector`);
}
}
} Type guard
function isCandidate(c: unknown): c is { label: string; ingest: unknown[] } {
return typeof c === 'object' && c !== null
&& typeof (c as any).label === 'string'
&& Array.isArray((c as any).ingest) && (c as any).ingest.length > 0;
} Prevention
- Build candidates with a factory that always attaches a non-empty ingest array.
- Filter candidates AFTER confirming ingest is non-empty, not before.
- Log candidate labels during construction to localise failures.
When it happens
Trigger: A candidate object whose `ingest` is omitted, set to null, not an array, or an empty array []. The check runs inside rawCandidates.map after the label is validated, so the error names the candidate label.
Common situations: Building candidates programmatically and filtering out all ingest records before passing; passing a candidate that only declares a branchPath but no ingest; a template that stubs ingest: [] as a placeholder.
Related errors
- scoreBy='nearest' requires a probe vector
- records must be a non-empty array of {id?, vector, text?}
- each record requires a non-empty numeric vector
- vector must be a non-empty numeric array
- Key exceeds maximum nesting depth of ${MAX_NESTING_DEPTH}
AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12).
Data as JSON: /api/errors/180e0453e22aeada.
Report an issue: GitHub.