ruvnet/ruflo · error
No query executor configured
Error message
No query executor configured
What it means
Thrown by AttentionExecutor.executeSQL() (attention-executor.ts:250) when the class has no SQL runner bound. The executor generates PostgreSQL RuVector SQL for attention mechanisms and needs a callback of type (sql: string) => Promise<unknown> to send that SQL to a database; it is stored as nullable and only assigned through setQueryExecutor(). Note that the public execute() method guards with 'if (this.queryExecutor)' and otherwise falls back to local computeBatch(), so this throw fires on code paths that call executeSQL() directly (e.g. subclasses or custom execution paths) without ever binding an executor.
Source
Thrown at v3/@claude-flow/plugins/src/integrations/ruvector/attention-executor.ts:250
/**
* Generate SQL without execution.
*/
generateSQL(mechanism: AttentionMechanism, input: AttentionInput): string {
return this.registry.get(mechanism).toSQL(input);
}
/**
* Generate batch SQL.
*/
generateBatchSQL(mechanism: AttentionMechanism, inputs: AttentionInput[]): string {
const sqls = inputs.map(input => this.generateSQL(mechanism, input));
return `WITH batch_attention AS (\n ${sqls.join(',\n ')}\n)\nSELECT * FROM batch_attention;`;
}
private async executeSQL(sql: string, timeoutMs?: number): Promise<unknown> {
if (!this.queryExecutor) {
throw new Error('No query executor configured');
}
if (timeoutMs) {
return Promise.race([
this.queryExecutor(sql),
new Promise((_, reject) =>
setTimeout(() => reject(new Error('Query timeout')), timeoutMs)
),
]);
}
return this.queryExecutor(sql);
}
private parseResult(result: unknown): number[][] {
if (Array.isArray(result)) {
return result.map(row => {
if (Array.isArray(row)) return row;View on GitHub (pinned to fa13ee4ad6)
Solutions
- Call executor.setQueryExecutor(sql => pool.query(sql)) once after construction, before any execution
- Verify you are not on a dryRun path: execute() with dryRun:true returns early with SQL only, but custom executeSQL callers still need the binding
- If you extended AttentionExecutor, ensure your override path either sets an executor or uses the local computeBatch fallback like execute() does
- Add a startup assertion that logs/throws early when the executor is meant to run against PostgreSQL but no query executor was injected
Example fix
// before
const executor = new AttentionExecutor(createDefaultRegistry());
const result = await executor.execute('self', input); // fine (local fallback)
await runSqlDirectly(executor); // throws: No query executor configured
// after
const executor = new AttentionExecutor(createDefaultRegistry());
executor.setQueryExecutor(sql => pool.query(sql));
const result = await executor.execute('self', input); Defensive patterns
Strategy: validation
Validate before calling
// Ensure the executor is bound to a SQL runner before any DB-backed execution.
// Note: AttentionExecutor has no public isConfigured(); track it at the call site.
let sqlBound = false;
function bindExecutor(executor: AttentionExecutor, pool: { query: (sql: string) => Promise<unknown> }) {
executor.setQueryExecutor(sql => pool.query(sql));
sqlBound = true;
}
function assertSqlReady() {
if (!sqlBound) throw new Error('AttentionExecutor used before setQueryExecutor()');
} Try / catch
try {
const result = await executor.execute(mechanism, input);
} catch (err) {
if (err instanceof Error && err.message === 'No query executor configured') {
// bind a runner and retry, or degrade to the local computeBatch path
executor.setQueryExecutor(sql => pool.query(sql));
return executor.execute(mechanism, input);
}
throw err;
} Prevention
- Call setQueryExecutor(sql => pool.query(sql)) immediately after constructing AttentionExecutor
- Remember execute() silently falls back to local computation when no executor is set — assert the binding when you specifically need PostgreSQL execution
- In DI setups, make the pool a constructor-time dependency so the executor cannot be created without it
When it happens
Trigger: Constructing new AttentionExecutor(registry) and invoking a code path that reaches executeSQL() without first calling setQueryExecutor(fn); subclassing AttentionExecutor and calling the private executeSQL via ts-ignore/cast; binding the executor conditionally (only when a pool exists) so some runtime paths skip it.
Common situations: Wiring RuVector attention into a new app and forgetting to pass the pg Pool query function; DI container creating the executor but not the SQL runner; test harness using dryRun:false without a mock executor; refactors that move setQueryExecutor behind an env check that evaluates false.
Related errors
- Flash attention not initialized
- MoE attention not initialized
- Hyperbolic attention not initialized
- Hard negative miner not initialized
- Attention mechanism '${type}' not registered
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/efaf947efa84f13d.
Report an issue: GitHub.