moeru-ai/airi · error · TypeError

botCall: bot.${method} is not a function

Error message

botCall: bot.${method} is not a function

What it means

Thrown as a TypeError by callBotMethod when bot[method] is not a function after passing the denylist. This means the method name passed the security check but does not exist on the mineflayer bot object or is not callable (e.g. a property, undefined, or a typo). It is a TypeError (not Error) to distinguish a missing API from the denylist rejection.

Source

Thrown at integrations/minecraft/src/cognitive/conscious/js-planner.ts:604

 * Use when:
 * - A script needs a low-level bot action that has no dedicated tool (e.g. `lookAt`).
 *
 * Expects:
 * - `method` is not in {@link BOT_METHOD_DENYLIST} and resolves to a bot function.
 * - `rawArgs` are sandbox-serializable; position-shaped args are marshaled to `Vec3`.
 *
 * Returns:
 * - The method's result, defensively cloned to a sandbox-safe value (or `null` when
 *   the result is a live object that cannot be serialized back).
 */
async function callBotMethod(mineflayer: Mineflayer, method: string, rawArgs: unknown): Promise<unknown> {
  if (BOT_METHOD_DENYLIST.has(method))
    throw new Error(`botCall: method "${method}" is not allowed`)

  const bot = mineflayer.bot as unknown as Record<string, unknown>
  const fn = bot[method]
  if (typeof fn !== 'function')
    throw new TypeError(`botCall: bot.${method} is not a function`)

  const callArgs = Array.isArray(rawArgs) ? rawArgs.map(marshalBotArg) : []
  const result = await (fn as (...a: unknown[]) => unknown).apply(bot, callArgs)

  try {
    return cloneStructured(result)
  }
  catch {
    // Live objects (Entity/Block/etc.) are not serializable back into the sandbox.
    return null
  }
}

export function extractJavaScriptCandidate(input: string): string {
  const trimmed = input.trim()
  // Prefer a fenced code block found ANYWHERE in the reply: chat-style models often add a short line
  // of reasoning before the code. The previous `^...$` anchoring only matched a reply that was nothing
  // but a fence, so any leading prose caused the entire prose+code to be executed as a script.

View on GitHub (pinned to 27111382b4)

Solutions

  1. Check the mineflayer API docs/bot object for the exact method name before calling.
  2. Inspect Object.keys(bot) (or the mineflayer types) to confirm the method exists at the root.
  3. For nested APIs (pathfinder, etc.), use the dedicated action tools rather than botCall.
  4. Catch TypeError distinctly from the denylist Error to give clearer feedback to the script generator.

Example fix

// before (sandboxed script)
botCall('lookAtBoss', { x: 1, y: 2, z: 3 })  // not a function
// after
botCall('lookAt', { x: 1, y: 2, z: 3 })
Defensive patterns

Strategy: type-guard

Validate before calling

function isBotMethod(bot, method) {
  return typeof (bot as any)[method] === 'function'
}
if (!isBotMethod(bot, method))
  // check the mineflayer API for the correct name

Type guard

function isBotMethod(bot, method) {
  return typeof (bot as Record<string, unknown>)[method] === 'function'
}

Try / catch

try {
  await callBotMethod(mineflayer, method, args)
} catch (e) {
  if (e instanceof TypeError && e.message.includes('is not a function'))
    // verify method name against the mineflayer bot object; regenerate script
  throw e
}

Prevention

When it happens

Trigger: A sandboxed script calls botCall with a misspelled method (e.g. 'lookAtBoss' instead of 'lookAt'); referencing a property that is not a function (e.g. 'health'); the method exists on a nested object, not the bot root; mineflayer version removed/renamed the method.

Common situations: LLM hallucinates a bot method that does not exist; the script assumes an API from a different mineflayer version; the method is namespaced (e.g. bot.pathfinder.goto) and cannot be reached via a flat botCall string.

Related errors


AI-assisted analysis of moeru-ai/airi@27111382b4 (2026-08-12). Data as JSON: /api/errors/83e919942fb16c0d. Report an issue: GitHub.