Budibase/budibase · error · Error

Agent _id is required

Error message

Agent _id is required

What it means

buildPromptAndTools requires the agent document to have an _id so prompt/tool results can be keyed to a stable agent identifier. When agent._id is absent (an unsaved or partially constructed Agent object) it throws a plain Error early, before loading tools and building the prompt.

Source

Thrown at packages/server/src/sdk/workspace/ai/agents/utils.ts:190

export async function buildPromptAndTools(
  agent: Agent,
  operation?: AgentOperation,
  options: BuildPromptAndToolsOptions = {}
): Promise<{
  systemPrompt: string
  tools: ToolSet
  toolDisplayNames: Record<string, string>
  toolSources: Record<string, string | undefined>
}> {
  const {
    baseSystemPrompt,
    includeGoal = true,
    fallbackPromptInstructions,
  } = options
  const agentId = agent._id
  if (!agentId) {
    throw new Error("Agent _id is required")
  }
  const hasKnowledgeBases = operation?.knowledgeBases?.some(Boolean) ?? false

  const allTools = await getAvailableTools(agent.aiconfig)
  const toolConfigs = operation?.enabledTools || []
  const enabledToolNames = new Set(toolConfigs.map(config => config.toolName))
  const configuredTools = allTools.filter(
    tool => enabledToolNames.has(tool.name) && !isHelperTool(tool)
  )
  let enabledTools = options.toolSecurityEnabled
    ? configuredTools
    : addLegacyHelperTools(configuredTools, allTools)

  if (options.toolSecurityEnabled && options.executionContext) {
    const executionContext = options.executionContext
    const visibilityByTable = new Map<string, Promise<boolean>>()
    enabledTools = await Promise.all(
      enabledTools.map(async tool => {

View on GitHub (pinned to a81a902e9a)

Solutions

  1. Save the agent first so it has an _id, then pass the persisted document to buildPromptAndTools.
  2. Validate agent._id before invoking any prompt/tool entry points.
  3. Fix data-mapping code that reconstructs Agent objects and omits _id.

Example fix

// before
await promptAndTools(draftAgent, operation) // throws
// after
const saved = await sdk.agents.create(draftAgent)
if (!saved._id) throw new Error("Agent must be saved")
await promptAndTools(saved, operation)
Defensive patterns

Strategy: type-guard

Validate before calling

if (!agent._id) {
  throw new Error("Persist the agent before building prompt and tools")
}
await buildPromptAndTools(agent, operation, options)

Type guard

const isPersistedAgent = (agent: Agent): agent is Agent & { _id: string } =>
  typeof agent._id === "string" && agent._id.length > 0

Try / catch

try {
  const { prompt, tools } = await promptAndTools(agent, operation)
} catch (err) {
  if ((err as Error).message === "Agent _id is required") {
    // save the agent then retry with the persisted document
  }
}

Prevention

When it happens

Trigger: Calling buildPromptAndTools (directly or via promptAndTools/result/legacyResult/securedResult) with an Agent instance lacking _id - e.g. an agent created in memory but not yet saved, or deserialized from a payload that stripped _id.

Common situations: Building agents via API POST before persisting and then immediately trying to run them; mapping over agent records and dropping _id; test fixtures without _id.

Related errors


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