openclaw - ✅(Solved) Fix [Bug]: A single broken plugin's malformed tool schema crashes every Anthropic agent run [1 pull requests]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

When any loaded plugin registers a tool whose schema is stored under the wrong key (e.g., inputSchema instead of parameters), the Anthropic tool-conversion adapter throws TypeError: Cannot read properties of undefined (reading 'properties') while building the tool list, and every subsequent agent run on any Anthropic model hits isError=true before the model ever sees the user message.

The error is never surfaced as an informative "plugin X has a broken tool Y" — the agent just silently fails every turn.

This turns a single broken 3rd-party plugin into a platform-wide hard outage for Claude users.

Error Message

The error is never surfaced as an informative "plugin X has a broken tool Y" — error=Cannot read properties of undefined (reading 'properties') log.warn(tool ${tool.name} has no schema; skipping); log.warn(tool ${tool.name} failed schema conversion: ${err.message});

Observe: isError=true, error=Cannot read properties of undefined (reading 'properties')

Root Cause

Root cause in OpenClaw

Fix Action

Fixed

PR fix notes

PR #69432: fix: guard Anthropic tool schema conversion against malformed plugin schemas

Description (problem / solution / changelog)

Summary

  • guard Anthropic tool conversion when a plugin tool omits parameters
  • accept inputSchema as a fallback alias during Anthropic payload building
  • add regression tests covering both the alias path and a fully malformed tool

Problem

A single plugin tool with a malformed schema could crash every Anthropic agent run before the model received the user message.

Root cause

src/agents/anthropic-transport-stream.ts assumed every tool exposed tool.parameters, then unconditionally read tool.parameters.properties and tool.parameters.required. If a third-party plugin registered a tool with inputSchema instead, or omitted the schema entirely, tool-list construction threw and the whole Anthropic run failed.

Fix

  • add resolveAnthropicToolInputSchema() to normalize the schema used for Anthropic input_schema
  • prefer tool.parameters when present
  • fall back to tool.inputSchema when a plugin uses that key
  • if neither shape is usable, emit an empty object schema instead of throwing

Tests

  • added a regression test proving Anthropic payload generation accepts plugin tools that use inputSchema
  • added a regression test proving a malformed tool without any schema now degrades to an empty object schema instead of crashing
  • verified with pnpm vitest run src/agents/anthropic-transport-stream.test.ts

Notes

The repo currently has unrelated pre-existing TypeScript failures in src/plugins/pi-package-graph.test.ts, so the full pre-commit pnpm check hook still fails outside this change.

Closes #69423

Changed files

  • src/agents/anthropic-transport-stream.test.ts (modified, +68/-0)
  • src/agents/anthropic-transport-stream.ts (modified, +31/-5)
  • src/agents/pi-embedded-runner/run.incomplete-turn.test.ts (modified, +43/-0)
  • src/agents/pi-embedded-runner/run.ts (modified, +10/-3)
  • src/agents/pi-embedded-runner/run/payloads.test.ts (modified, +32/-0)
  • src/agents/pi-embedded-runner/run/payloads.ts (modified, +3/-2)
  • src/config/io.ts (modified, +13/-9)
  • src/config/io.write-config.test.ts (modified, +138/-2)
  • src/gateway/server/ws-connection/handshake-auth-helpers.test.ts (modified, +22/-10)
  • src/gateway/server/ws-connection/handshake-auth-helpers.ts (modified, +1/-3)
  • ui/src/ui/controllers/chat.test.ts (modified, +82/-0)
  • ui/src/ui/controllers/chat.ts (modified, +65/-1)

Code Example

embedded run agent end: ... isError=true
  model=claude-opus-4-7 provider=anthropic
  error=Cannot read properties of undefined (reading 'properties')

---

function convertAnthropicTools(tools, isOAuthToken) {
    if (!tools) return [];
    return tools.map((tool) => ({
        name: ...,
        description: tool.description,
        input_schema: {
            type: "object",
            properties: tool.parameters.properties || {},   // ← throws on undefined
            required: tool.parameters.required || []
        }
    }));
}

---

function convertAnthropicTools(tools, isOAuthToken) {
    if (!tools) return [];
    const out = [];
    for (const tool of tools) {
        try {
            const schema = tool.parameters ?? tool.inputSchema; // accept both
            if (!schema || typeof schema !== "object") {
                log.warn(`tool ${tool.name} has no schema; skipping`);
                continue;
            }
            out.push({
                name: ...,
                description: tool.description,
                input_schema: {
                    type: "object",
                    properties: schema.properties || {},
                    required: schema.required || []
                }
            });
        } catch (err) {
            log.warn(`tool ${tool.name} failed schema conversion: ${err.message}`);
        }
    }
    return out;
}

---

# Install a plugin whose index.js uses `inputSchema:` instead of `parameters:`
openclaw plugins install @agntdata/openclaw-x@1.0.13
# or any test fixture with registerTool({ name: "foo", inputSchema: {...} })

# Run any Claude agent turn
openclaw exec "say hi"
# Observe: isError=true, error=Cannot read properties of undefined (reading 'properties')
RAW_BUFFERClick to expand / collapse

[Bug]: A single broken plugin's malformed tool schema crashes every agent run (no per-tool isolation in Anthropic adapter)

Summary

When any loaded plugin registers a tool whose schema is stored under the wrong key (e.g., inputSchema instead of parameters), the Anthropic tool-conversion adapter throws TypeError: Cannot read properties of undefined (reading 'properties') while building the tool list, and every subsequent agent run on any Anthropic model hits isError=true before the model ever sees the user message.

The error is never surfaced as an informative "plugin X has a broken tool Y" — the agent just silently fails every turn.

This turns a single broken 3rd-party plugin into a platform-wide hard outage for Claude users.

Observed in the wild

Plugin: @agntdata/[email protected] (filing a bug report against them separately — their schema key is inputSchema, OpenClaw's contract is parameters).

Symptom: every claude-* agent session (main agent, slug generator, subagents, named sessions) hits:

embedded run agent end: ... isError=true
  model=claude-opus-4-7 provider=anthropic
  error=Cannot read properties of undefined (reading 'properties')

Disabling the plugin (mv ~/.openclaw/extensions/agntdata-x ~/.openclaw/extensions/agntdata-x.disabled) immediately restores service.

Root cause in OpenClaw

dist/anthropic-vertex-stream-*.js (the Anthropic adapter):

function convertAnthropicTools(tools, isOAuthToken) {
    if (!tools) return [];
    return tools.map((tool) => ({
        name: ...,
        description: tool.description,
        input_schema: {
            type: "object",
            properties: tool.parameters.properties || {},   // ← throws on undefined
            required: tool.parameters.required || []
        }
    }));
}
  • No defensive handling of tool.parameters === undefined
  • No try/catch around per-tool conversion; one broken tool throws and the whole list-building fails
  • No validation at plugin-load time that parameters (or inputSchema, etc.) actually exists on registered tools

Proposed fix (ranked by impact/effort)

1. Defensive per-tool conversion (cheap, high value)

Wrap each tool's conversion in try/catch and drop bad tools rather than crash the whole agent:

function convertAnthropicTools(tools, isOAuthToken) {
    if (!tools) return [];
    const out = [];
    for (const tool of tools) {
        try {
            const schema = tool.parameters ?? tool.inputSchema; // accept both
            if (!schema || typeof schema !== "object") {
                log.warn(`tool ${tool.name} has no schema; skipping`);
                continue;
            }
            out.push({
                name: ...,
                description: tool.description,
                input_schema: {
                    type: "object",
                    properties: schema.properties || {},
                    required: schema.required || []
                }
            });
        } catch (err) {
            log.warn(`tool ${tool.name} failed schema conversion: ${err.message}`);
        }
    }
    return out;
}

2. Validate at registerTool() time (prevents pollution)

When a plugin calls api.registerTool(), validate that one of the expected schema keys is present and well-formed. If not, log and reject the registration rather than silently accept it.

Bonus: accept both parameters and inputSchema (the latter matches Anthropic's own native format and the MCP spec, so it's a reasonable alias). Normalize to one canonical internal shape.

3. Surface plugin errors in openclaw status

Today the fact that a plugin broke every agent run only surfaces in embedded run agent end log lines. A better UX: show broken plugins in openclaw status with a one-line reason, so users can see "plugin X failed to load N tools because of schema errors" without tailing logs.

4. Gate-check on plugin install

openclaw plugins install could run a dry conversion pass on every registerTool() call and refuse to mark the plugin enabled if any tool fails schema conversion. That would have caught this at install time rather than at first agent turn.

Repro

# Install a plugin whose index.js uses `inputSchema:` instead of `parameters:`
openclaw plugins install @agntdata/[email protected]
# or any test fixture with registerTool({ name: "foo", inputSchema: {...} })

# Run any Claude agent turn
openclaw exec "say hi"
# Observe: isError=true, error=Cannot read properties of undefined (reading 'properties')

Environment

  • OpenClaw 2026.4.15 (041266a)
  • Node v25.9.0
  • macOS Darwin 25.3.0 arm64
  • Affected models: claude-opus-4-7, claude-sonnet-4-6, claude-haiku-4-5
  • Affected sessions: main agent, slug-generator, subagents, named sessions
  • Not affected: OpenAI models (different adapter; they may have their own equivalent brittleness — worth a parallel audit)

Severity

High. One broken 3rd-party plugin makes OpenClaw unusable for Anthropic users. The fix is a ~20-line defensive try/catch.

extent analysis

TL;DR

The most likely fix is to implement defensive per-tool conversion by wrapping each tool's conversion in a try/catch block and dropping bad tools rather than crashing the whole agent.

Guidance

  • Implement a try/catch block around the tool conversion code to catch and handle any errors that occur during the conversion process.
  • Validate the existence and format of the parameters or inputSchema property in the tool object before attempting to access its properties.
  • Consider adding a validation step at plugin registration time to prevent plugins with malformed tool schemas from being registered.
  • Surface plugin errors in the openclaw status command to provide users with more informative error messages.

Example

function convertAnthropicTools(tools, isOAuthToken) {
    if (!tools) return [];
    const out = [];
    for (const tool of tools) {
        try {
            const schema = tool.parameters ?? tool.inputSchema; 
            if (!schema || typeof schema !== "object") {
                log.warn(`tool ${tool.name} has no schema; skipping`);
                continue;
            }
            out.push({
                name: ...,
                description: tool.description,
                input_schema: {
                    type: "object",
                    properties: schema.properties || {},
                    required: schema.required || []
                }
            });
        } catch (err) {
            log.warn(`tool ${tool.name} failed schema conversion: ${err.message}`);
        }
    }
    return out;
}

Notes

The proposed fix is a relatively simple and low-risk change that can help prevent the entire agent from crashing due to a single broken plugin. However, it may not address the underlying issue with the plugin's malformed tool schema, and additional validation and error handling may be necessary to ensure the stability of the system.

Recommendation

Apply the defensive per-tool conversion workaround to prevent the agent from crashing due to a single broken plugin. This fix is a relatively simple and low-risk change that can help improve the stability of the system.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: A single broken plugin's malformed tool schema crashes every Anthropic agent run [1 pull requests]