Budibase/budibase · error

Cannot create a query tool without a query ID

Error message

Cannot create a query tool without a query ID

What it means

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.

Source

Thrown at packages/server/src/ai/tools/restQuery.ts:61

  for (const param of query.parameters || []) {
    schemaFields[param.name] = z
      .string()
      .optional()
      .describe(`Parameter: ${param.name}`)
  }

  return z.object(schemaFields)
}

const createQueryTool = ({
  query,
  sourceType,
  sourceLabel,
  sourceIconType,
  description,
}: QueryToolOptions): AiToolDefinition => {
  if (!query._id) {
    throw new Error("Cannot create a query tool without a query ID")
  }
  const { runtimeBinding: toolName } = getQueryToolBindings({
    sourceType,
    sourceLabel,
    queryName: query.name,
    queryId: query._id,
  })
  const parametersSchema = buildParametersSchema(query)

  return {
    name: toolName,
    readableName: query.name,
    sourceId: query._id,
    description,
    sourceType,
    sourceLabel,
    sourceIconType,
    executionPolicy: {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Persist the query first and use the returned document with _id
  2. Ensure the query fetch includes _id (don't strip fields)
  3. Validate query._id exists before calling createQueryTool

Example fix

// before
const tool = createRestQueryTool({ query: { name: "q", ... } })
// after
const saved = await saveQuery({ name: "q", ... })
const tool = createRestQueryTool({ query: saved }) // saved._id present
Defensive patterns

Strategy: validation

Validate before calling

if (!query._id) throw new Error("Query must be saved before creating a tool")

Type guard

const hasId = (q: Query): q is Query & { _id: string } => typeof q._id === "string" && q._id.length > 0

Try / catch

try { const tool = createRestQueryTool({ query }) } catch (e) { if (e.message.includes("without a query ID")) { /* persist query first */ } else throw e }

Prevention

When it happens

Trigger: 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.

Common situations: Passing a newly built query payload instead of the persisted document; forgetting to await the save before creating the tool; projections that omit _id.

Related errors


AI-assisted analysis of Budibase/budibase@a81a902e9a (2026-08-29). Data as JSON: /api/errors/bb2b3b2c22e387d0. Report an issue: GitHub.