{"record":{"id":"bb2b3b2c22e387d0","repo":"Budibase/budibase","slug":"cannot-create-a-query-tool-without-a-query-id","errorCode":null,"errorMessage":"Cannot create a query tool without a query ID","messagePattern":"Cannot create a query tool without a query ID","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/server/src/ai/tools/restQuery.ts","lineNumber":61,"sourceCode":"  for (const param of query.parameters || []) {\n    schemaFields[param.name] = z\n      .string()\n      .optional()\n      .describe(`Parameter: ${param.name}`)\n  }\n\n  return z.object(schemaFields)\n}\n\nconst createQueryTool = ({\n  query,\n  sourceType,\n  sourceLabel,\n  sourceIconType,\n  description,\n}: QueryToolOptions): AiToolDefinition => {\n  if (!query._id) {\n    throw new Error(\"Cannot create a query tool without a query ID\")\n  }\n  const { runtimeBinding: toolName } = getQueryToolBindings({\n    sourceType,\n    sourceLabel,\n    queryName: query.name,\n    queryId: query._id,\n  })\n  const parametersSchema = buildParametersSchema(query)\n\n  return {\n    name: toolName,\n    readableName: query.name,\n    sourceId: query._id,\n    description,\n    sourceType,\n    sourceLabel,\n    sourceIconType,\n    executionPolicy: {","sourceCodeStart":43,"sourceCodeEnd":79,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/server/src/ai/tools/restQuery.ts#L43-L79","documentation":"createQueryTool builds an AI tool bound to a stored query and requires the query document to have an _id to construct the tool name and identifiers. If a query object without a persisted _id is passed, creation fails immediately.","triggerScenarios":"Calling createRestQueryTool or createDatasourceQueryTool with a query object that has never been saved (no _id), e.g. constructed in memory or fetched without _id included.","commonSituations":"Passing a newly built query payload instead of the persisted document; forgetting to await the save before creating the tool; projections that omit _id.","solutions":["Persist the query first and use the returned document with _id","Ensure the query fetch includes _id (don't strip fields)","Validate query._id exists before calling createQueryTool"],"exampleFix":"// before\nconst tool = createRestQueryTool({ query: { name: \"q\", ... } })\n// after\nconst saved = await saveQuery({ name: \"q\", ... })\nconst tool = createRestQueryTool({ query: saved }) // saved._id present","handlingStrategy":"validation","validationCode":"if (!query._id) throw new Error(\"Query must be saved before creating a tool\")","typeGuard":"const hasId = (q: Query): q is Query & { _id: string } => typeof q._id === \"string\" && q._id.length > 0","tryCatchPattern":"try { const tool = createRestQueryTool({ query }) } catch (e) { if (e.message.includes(\"without a query ID\")) { /* persist query first */ } else throw e }","preventionTips":["Always persist queries before building tools from them","Assert _id presence in query-loading helpers","Avoid projections that omit _id when fetching queries for tools"],"tags":["ai","tools","validation"],"backgroundTag":"missing-required-identifier","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}