decolua/9router · error

Kiro toolUseEvent is missing a tool name

Error message

Kiro toolUseEvent is missing a tool name

What it means

Within a toolUseEvent fragment the executor derives the tool name and requires a non-empty string after trimming. A missing or empty 'name' makes the tool call unidentifiable — the executor cannot construct a function_call for the client — so it throws. This surfaces upstream protocol violations immediately instead of emitting an anonymous tool call.

Source

Thrown at open-sse/executors/kiro.js:832

      } else if (eventType === "reasoningContentEvent") {
        const value = event.payload?.reasoningContentEvent || event.payload || {};
        const content = typeof value === "string" ? value : value.text || value.content || "";
        if (content) {
          state.hasReasoning = true;
          state.totalContentLength += content.length;
          emitDelta(controller, { reasoning_content: content });
        }
      } else if (eventType === "codeEvent" && typeof event.payload?.content === "string") {
        state.hasCode = true;
        state.totalContentLength += event.payload.content.length;
        emitDelta(controller, { content: event.payload.content });
      } else if (eventType === "toolUseEvent") {
        state.sawToolUse = true;
        const values = Array.isArray(event.payload) ? event.payload : [event.payload];
        if (!values[0]) throw new Error("Kiro toolUseEvent is empty");
        for (const value of values) {
          const name = typeof value?.name === "string" ? value.name.trim() : "";
          if (!name) throw new Error("Kiro toolUseEvent is missing a tool name");
          let id;
          if (value.toolUseId == null) {
            id = `call_${created}_${state.tools.size + 1}`;
          } else if (typeof value.toolUseId !== "string" || !value.toolUseId.trim()) {
            throw new Error("Kiro toolUseEvent has an invalid toolUseId");
          } else {
            id = value.toolUseId;
          }
          let tool = state.tools.get(id);
          if (!tool) {
            tool = { id, name };
            state.tools.set(id, tool);
            state.bufferedToolBytes += encoder.encode(id).byteLength + encoder.encode(name).byteLength + 32;
            assertToolBufferBound();
          } else if (tool.name !== name) {
            throw new Error("Kiro tool name changed between fragments");
          }
          appendToolInput(tool, value.input);

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Retry the request once — this is often a transient malformed fragment from the upstream
  2. Check the installed Kiro upstream API contract for a renamed/moved name field and update the executor's field extraction
  3. Log the full toolUseEvent payload on this path to confirm the actual shape being received
  4. If only the input-fragment frames lack name (name sent on first frame only), make the executor carry-forward the name for known toolUseId instead of throwing

Example fix

// before: strict per-fragment name requirement
const name = typeof value?.name === 'string' ? value.name.trim() : '';
if (!name) throw new Error('Kiro toolUseEvent is missing a tool name');
// after: fall back to name already recorded for this toolUseId (continuation fragments)
let name = typeof value?.name === 'string' ? value.name.trim() : '';
if (!name && value?.toolUseId) name = state.tools.get(value.toolUseId)?.name || '';
if (!name) throw new Error('Kiro toolUseEvent is missing a tool name');
Defensive patterns

Strategy: try-catch

Type guard

function isNamedToolFragment(value) {
  return Boolean(value) && typeof value.name === 'string' && value.name.trim().length > 0;
}

Try / catch

try {
  return await streamKiro(req);
} catch (e) {
  if (/toolUseEvent is missing a tool name/.test(e.message)) {
    logRawEventForDebug(e); // capture surrounding EventStream frames
    if (attempts < 2) return retry(req);
  }
  throw e;
}

Prevention

When it happens

Trigger: A toolUseEvent value where value is null/undefined, value.name is not a string, or value.name trims to an empty string — e.g. Kiro sent a fragment carrying only input deltas before the fragment containing the name, or the name field was renamed in an upstream API update.

Common situations: Upstream API/protocol changes renaming the 'name' field; streaming implementations that split tool metadata across frames; model emitting degenerate tool calls with blank names under heavy load or near context limits.

Understand the failure class

Background: "Missing required field" and "field is required" errors: why libraries reject payloads that omit mandatory fields — this error's family across 20 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/0e2928745fec0d67. Report an issue: GitHub.