Budibase/budibase · error

${failureMessage}

Error message

${failureMessage}

What it means

The tool's execute returned a result flagged as a failure by getToolFailure; wrappedExecute converts that into a thrown Error carrying the failure message. It surfaces tool-level logical failures (as opposed to exceptions) so the calling agent sees them as errors.

Solutions

  1. Fix the underlying tool failure indicated by the message (inspect the message text for the real cause)
  2. Check the upstream query/API the tool invokes and ensure credentials/parameters are valid
  3. Handle the thrown error in the agent loop and retry with corrected input

Example fix

// before
const result = await tool.execute(input) // result carries failure, thrown here
// after
try {
  await tool.execute(input)
} catch (e) {
  // inspect e.message from getToolFailure to find the root cause
}
Defensive patterns

Strategy: try-catch

Validate before calling

const result = await execute(input, options); const failure = getToolFailure(result); if (failure) { /* handle before it becomes a throw */ }

Try / catch

try { await tool.run(input) } catch (e) { log.error("tool failure:", e.message); /* retry or surface to agent */ }

Prevention

When it happens

Trigger: A tool's execute() returns a result object whose failure field/message is populated, e.g. an upstream API error captured into the result rather than thrown.

Common situations: Query tool calls a REST query that returns an error status; search tool gets an API error and encodes it in the result; tool implementation sets failureMessage on partial failure.

Related errors


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

Appendix: source

Thrown at packages/server/src/ai/tools/index.ts:133

      }
      await runtime.authorize({
        authorization: toolDef.authorization,
        input,
        executionContext: runtime.executionContext,
        principal: runtime.principal,
      })
    }
    if (gate) {
      return await gate.intercept(input, {
        toolCallId: options?.toolCallId ?? "",
        messages: options?.messages,
      })
    }
    try {
      const result = await execute(input, options)
      const failureMessage = getToolFailure(result)
      if (failureMessage) {
        throw new Error(failureMessage)
      }
      const authorizedResult =
        runtime && toolDef.filterResult
          ? await toolDef.filterResult(result, runtime)
          : result
      if (runtime) {
        logToolExecution("success", toolDef, runtime)
      }
      return authorizedResult
    } catch (error) {
      if (runtime) {
        logToolExecution("error", toolDef, runtime)
      }
      throw error
    }
  }

  return {

View on GitHub (pinned to a81a902e9a)