Skip to content

[Bug]: A single broken plugin's malformed tool schema crashes every Anthropic agent run #69423

Description

@jmnickels

[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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions