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

  1. Ensure every candidate includes ingest: [{ vector: [...] }] with at least one vector record.
  2. If a candidate legitimately has no data, drop it from the candidates array rather than passing an empty ingest.
  3. Validate the candidates array shape before calling the tool (see defense validationCode).
  4. 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

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


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/180e0453e22aeada. Report an issue: GitHub.