{"record":{"id":"efaf947efa84f13d","repo":"ruvnet/ruflo","slug":"no-query-executor-configured","errorCode":null,"errorMessage":"No query executor configured","messagePattern":"No query executor configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/plugins/src/integrations/ruvector/attention-executor.ts","lineNumber":250,"sourceCode":"\n  /**\n   * Generate SQL without execution.\n   */\n  generateSQL(mechanism: AttentionMechanism, input: AttentionInput): string {\n    return this.registry.get(mechanism).toSQL(input);\n  }\n\n  /**\n   * Generate batch SQL.\n   */\n  generateBatchSQL(mechanism: AttentionMechanism, inputs: AttentionInput[]): string {\n    const sqls = inputs.map(input => this.generateSQL(mechanism, input));\n    return `WITH batch_attention AS (\\n  ${sqls.join(',\\n  ')}\\n)\\nSELECT * FROM batch_attention;`;\n  }\n\n  private async executeSQL(sql: string, timeoutMs?: number): Promise<unknown> {\n    if (!this.queryExecutor) {\n      throw new Error('No query executor configured');\n    }\n\n    if (timeoutMs) {\n      return Promise.race([\n        this.queryExecutor(sql),\n        new Promise((_, reject) =>\n          setTimeout(() => reject(new Error('Query timeout')), timeoutMs)\n        ),\n      ]);\n    }\n\n    return this.queryExecutor(sql);\n  }\n\n  private parseResult(result: unknown): number[][] {\n    if (Array.isArray(result)) {\n      return result.map(row => {\n        if (Array.isArray(row)) return row;","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/plugins/src/integrations/ruvector/attention-executor.ts#L232-L268","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst executor = new AttentionExecutor(createDefaultRegistry());\nconst result = await executor.execute('self', input); // fine (local fallback)\nawait runSqlDirectly(executor); // throws: No query executor configured\n\n// after\nconst executor = new AttentionExecutor(createDefaultRegistry());\nexecutor.setQueryExecutor(sql => pool.query(sql));\nconst result = await executor.execute('self', input);","handlingStrategy":"validation","validationCode":"// Ensure the executor is bound to a SQL runner before any DB-backed execution.\n// Note: AttentionExecutor has no public isConfigured(); track it at the call site.\nlet sqlBound = false;\nfunction bindExecutor(executor: AttentionExecutor, pool: { query: (sql: string) => Promise<unknown> }) {\n  executor.setQueryExecutor(sql => pool.query(sql));\n  sqlBound = true;\n}\nfunction assertSqlReady() {\n  if (!sqlBound) throw new Error('AttentionExecutor used before setQueryExecutor()');\n}","typeGuard":null,"tryCatchPattern":"try {\n  const result = await executor.execute(mechanism, input);\n} catch (err) {\n  if (err instanceof Error && err.message === 'No query executor configured') {\n    // bind a runner and retry, or degrade to the local computeBatch path\n    executor.setQueryExecutor(sql => pool.query(sql));\n    return executor.execute(mechanism, input);\n  }\n  throw err;\n}","preventionTips":["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"],"tags":["sql","configuration","dependency-injection","ruvector","attention"],"backgroundTag":"dependency-not-configured","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","contentChangedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}