{"record":{"id":"d52af0b3c5b9cb41","repo":"different-ai/openwork","slug":"invalidtoolinput","errorCode":"InvalidToolInput","errorMessage":"Tool '${name}' expects exactly one input object.","messagePattern":"Tool '(.+?)' expects exactly one input object\\.","errorType":"error_code","errorClass":"ToolRuntimeError","httpStatus":null,"severity":"error","filePath":"packages/codemode/src/tool-runtime.ts","lineNumber":773,"sourceCode":"  return {\n    root: new ToolReference([]),\n    calls,\n    keys: (path) => namespaceKeys(callableTools, path),\n    invoke: (path, args) =>\n      Effect.gen(function* () {\n        const name = path.join(\".\")\n        const externalArgs = args.map((arg) => copyOut(copyIn(arg, `Arguments for tool '${name}'`)))\n        const call = { name }\n        const recordAndObserve = (input: unknown) =>\n          Effect.sync(() => {\n            recordCall(call)\n            return calls.length - 1\n          }).pipe(Effect.tap((index) => hooks?.onToolCallStart?.({ index, name, input }) ?? Effect.void))\n        const tool = resolve(callableTools, path)\n        let describedInput: unknown\n        if (isDefinition(tool)) {\n          if (externalArgs.length !== 1)\n            throw new ToolRuntimeError(\"InvalidToolInput\", `Tool '${name}' expects exactly one input object.`)\n          describedInput = yield* Effect.try({\n            try: () => decodeToolInput(tool, externalArgs[0]),\n            catch: (cause) =>\n              new ToolRuntimeError(\"InvalidToolInput\", `Invalid input for tool '${name}': ${String(cause)}`),\n          })\n        }\n        const input = isDefinition(tool) ? describedInput : externalArgs\n        const index = yield* recordAndObserve(input)\n        const currentCall = { index, name, input }\n        if (isDefinition(tool)) {\n          return yield* observeEnd(\n            Effect.gen(function* () {\n              const raw = yield* runHost(Effect.suspend(() => tool.run(describedInput)))\n              const result = yield* Effect.try({\n                try: () => decodeToolOutput(tool, raw),\n                catch: () => new ToolRuntimeError(\"InvalidToolOutput\", `Invalid output from tool '${name}'.`),\n              })\n              return yield* decodeOutput(result, name)","sourceCodeStart":755,"sourceCodeEnd":791,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/packages/codemode/src/tool-runtime.ts#L755-L791","documentation":"Callable tools in codemode accept exactly one argument: a single input object matching the tool's schema. When the script calls a tool with zero arguments or more than one positional argument, the runtime throws InvalidToolInput before the tool runs. Spread the arguments into one object instead.","triggerScenarios":"Calling a tool from a codemode script as tool() or tool(a, b, c) — i.e. externalArgs.length !== 1 — instead of tool({...}) with one object argument.","commonSituations":"Porting scripts written for APIs where tools take individual positional parameters; forgetting the single input object entirely; dynamically forwarding multiple script variables to a tool via apply/spread without wrapping them.","solutions":["Wrap all arguments into one object: call the tool as tool({ param1: a, param2: b })","Check the tool's declared input schema and supply exactly one object whose fields match it","If arguments are already in an array, pass the object itself, not the spread: tool(argsObj) instead of tool(...args)","Log externalArgs before the call to confirm only one value is being passed"],"exampleFix":"// before\nconst result = yield* callTool('search', query, limit)\n// after\nconst result = yield* callTool('search', { query, limit })","handlingStrategy":"validation","validationCode":"function validateToolCall(args) {\n  if (!Array.isArray(args) || args.length !== 1 || typeof args[0] !== 'object' || args[0] === null) {\n    throw new Error('Tool calls must pass exactly one input object: tool({ ... })');\n  }\n}","typeGuard":"function isSingleInputObject(args: unknown[]): args is [Record<string, unknown>] {\n  return args.length === 1 && typeof args[0] === 'object' && args[0] !== null;\n}","tryCatchPattern":"try {\n  yield* callTool(name, input)\n} catch (e) {\n  if (e instanceof ToolRuntimeError && e.code === 'InvalidToolInput') {\n    console.error(`Bad input for ${name}: wrap args in one object`, e.message)\n  } else throw e\n}","preventionTips":["Always call tools as tool({ field: value }) with a single object","Read each tool's input schema before wiring calls","Never spread multiple variables directly as tool arguments","Lint/generate codemode scripts against the tool schema"],"tags":["codemode","tool-input","argument-validation"],"backgroundTag":"invalid-tool-arguments","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}