{"record":{"id":"be027550cf2e0e68","repo":"Budibase/budibase","slug":"cannot-generate-query-tool-bindings-without-a-quer","errorCode":null,"errorMessage":"Cannot generate query tool bindings without a query ID","messagePattern":"Cannot generate query tool bindings without a query ID","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/server/src/sdk/workspace/ai/agents/queryToolReferences.ts","lineNumber":127,"sourceCode":"    return {\n      ...operation,\n      promptInstructions,\n      enabledTools,\n    }\n  })\n\n  return changed ? { ...agent, operations } : undefined\n}\n\nconst getBindings = ({\n  datasource,\n  query,\n}: {\n  datasource: Datasource\n  query: Query\n}) => {\n  if (!query._id) {\n    throw new Error(\"Cannot generate query tool bindings without a query ID\")\n  }\n  const sourceType: QueryToolType =\n    datasource.source === SourceName.REST\n      ? ToolType.REST_QUERY\n      : ToolType.DATASOURCE_QUERY\n  return getQueryToolBindings({\n    sourceType,\n    sourceLabel:\n      datasource.name ||\n      (sourceType === ToolType.REST_QUERY ? \"API\" : \"Datasource\"),\n    queryName: query.name,\n    queryId: query._id,\n  })\n}\n\nexport const migrateQueryToolReferences = async (\n  migrations: QueryToolReferenceMigration | QueryToolReferenceMigration[]\n): Promise<void> => {","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/sdk/workspace/ai/agents/queryToolReferences.ts#L109-L145","documentation":"getBindings generates AI tool bindings for a query, which requires a persisted document ID. If query._id is missing (unsaved or in-memory query object), it cannot build stable binding references and throws a plain Error before computing the tool type (REST_QUERY vs DATASOURCE_QUERY).","triggerScenarios":"Calling getBindings({ datasource, query }) with a Query object that has not been saved to the database (_id undefined), e.g. building bindings for a newly drafted query before persisting it.","commonSituations":"Syncing query tool bindings during datasource import/edit flows before the query save completes; constructing a Query object manually in code or tests without an _id.","solutions":["Persist the query first (save/query API) so it has an _id, then call getBindings.","Validate query._id in the calling code and skip or defer binding generation for unsaved queries.","If constructing queries in tests/scripts, set a realistic _id before invoking getBindings."],"exampleFix":"// before\ngetBindings({ datasource, query: draftQuery }) // throws\n// after\nconst saved = await api.saveQuery(draftQuery)\nif (!saved._id) throw new Error(\"Query must be saved\")\ngetBindings({ datasource, query: saved })","handlingStrategy":"type-guard","validationCode":"if (!query._id) {\n  throw new Error(\"Save the query before generating tool bindings\")\n}\ngetBindings({ datasource, query })","typeGuard":"const isPersistedQuery = (query: Query): query is Query & { _id: string } =>\n  typeof query._id === \"string\" && query._id.length > 0","tryCatchPattern":"try {\n  const bindings = getBindings({ datasource, query })\n} catch (err) {\n  if ((err as Error).message.includes(\"without a query ID\")) {\n    // defer binding generation until the query is saved\n  }\n}","preventionTips":["Always persist queries before syncing agent tool bindings.","Gate binding-generation code paths behind an _id check.","In import/clone flows, save derived queries before computing bindings."],"tags":["validation","queries","agents"],"backgroundTag":"missing-required-id","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}