openclaw - 💡(How to fix) Fix [Bug]: Plugin TypeBox tool schemas rejected as 'missing parameters object' by describeMalformedPluginTool — memory tools silently dropped every turn [1 comments, 2 participants]

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…
GitHub stats
openclaw/openclaw#75244Fetched 2026-05-01 05:36:18
View on GitHub
Comments
1
Participants
2
Timeline
1
Reactions
2
Author
Timeline (top)
commented ×1

Plugin tools that use TypeBox Type.Object() schemas for their parameters field are rejected by OpenClaw's describeMalformedPluginTool validator with "missing parameters object" on every agent turn. The tools are silently dropped, the error is logged but never surfaced to the user, and the agent loses access to those tools without any indication.

In our case, the openclaw-remnic memory plugin's memory_search and memory_get tools are rejected every turn, causing:

  • Cascading context overflow (agent compensates with more tool calls without memory recall)
  • Stuck sessions (processing state for 5+ minutes)
  • Auto-compaction loops (93 messages, 171KB session, compaction takes 3.5 minutes)
  • Agent appears to "just stop responding" from the user's perspective

Error Message

Plugin tools that use TypeBox Type.Object() schemas for their parameters field are rejected by OpenClaw's describeMalformedPluginTool validator with "missing parameters object" on every agent turn. The tools are silently dropped, the error is logged but never surfaced to the user, and the agent loses access to those tools without any indication.

  • Silent tool loss: The agent loses critical tools with no user-visible error
  • Recurring: The error fires on EVERY agent turn (tools are re-registered and re-validated each turn), producing 2+ error log entries per turn

Root Cause

The validation in tools-Dt0Yx7_E.js:

function isRecord(value) {
    return Boolean(value && typeof value === "object" && !Array.isArray(value));
}

function describeMalformedPluginTool(tool) {
    if (!isRecord(tool)) return "tool must be an object";
    const name = readPluginToolName(tool);
    if (!name) return "missing non-empty name";
    if (typeof tool.execute !== "function") return `${name} missing execute function`;
    if (!isRecord(tool.parameters)) return `${name} missing parameters object`;
}

The tool object returned by buildMemorySearchTool:

{
    name: "memory_search",
    description: "Search Remnic memories for the OpenClaw active-memory surface.",
    parameters: MemorySearchInputSchema,  // TypeBox Type2.Object({query: Type2.String(), ...})
    execute: async function(...) { ... }
}

A TypeBox Type.Object() produces {type: "object", required: [...], properties: {...}} — a valid plain JS object that should pass isRecord(). Yet isRecord(tool.parameters) returns false at runtime.

Suspected cause: TypeBox version mismatch. The plugin ships @sinclair/[email protected] while OpenClaw bundles [email protected] (a different package entirely). When jiti loads the plugin in-process, there may be a resolution conflict where Type2.Object() produces a schema object that does not satisfy isRecord at validation time — possibly due to Symbol-based internal properties, class instances, or Proxies in the v1.x schema format.

The fact that other TypeBox-registered tools from the same plugin work (they use Type.Object() inline at the call site rather than referencing a module-level var) adds weight to a jiti/hoisting/resolution timing theory, though we could not definitively confirm this without adding debug logging to describeMalformedPluginTool.

Code Example

plugin tool is malformed (openclaw-remnic): memory_search missing parameters object
plugin tool is malformed (openclaw-remnic): memory_get missing parameters object

---

function isRecord(value) {
    return Boolean(value && typeof value === "object" && !Array.isArray(value));
}

function describeMalformedPluginTool(tool) {
    if (!isRecord(tool)) return "tool must be an object";
    const name = readPluginToolName(tool);
    if (!name) return "missing non-empty name";
    if (typeof tool.execute !== "function") return `${name} missing execute function`;
    if (!isRecord(tool.parameters)) return `${name} missing parameters object`;
}

---

{
    name: "memory_search",
    description: "Search Remnic memories for the OpenClaw active-memory surface.",
    parameters: MemorySearchInputSchema,  // TypeBox Type2.Object({query: Type2.String(), ...})
    execute: async function(...) { ... }
}

---

if (!isRecord(tool.parameters)) {
    return `${name} missing parameters object (got ${typeof tool.parameters}: ${JSON.stringify(tool.parameters)?.slice(0, 200)})`;
}

---

const schema = tool.parameters ?? tool.inputSchema;
if (!isRecord(schema)) return `${name} missing parameters object`;

---

function isValidToolSchema(value) {
    if (isRecord(value)) return true;
    if (value && typeof value === "object" && value[Symbol.for("@sinclair/typebox/Kind")]) return true;
    return false;
}
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Summary

Plugin tools that use TypeBox Type.Object() schemas for their parameters field are rejected by OpenClaw's describeMalformedPluginTool validator with "missing parameters object" on every agent turn. The tools are silently dropped, the error is logged but never surfaced to the user, and the agent loses access to those tools without any indication.

In our case, the openclaw-remnic memory plugin's memory_search and memory_get tools are rejected every turn, causing:

  • Cascading context overflow (agent compensates with more tool calls without memory recall)
  • Stuck sessions (processing state for 5+ minutes)
  • Auto-compaction loops (93 messages, 171KB session, compaction takes 3.5 minutes)
  • Agent appears to "just stop responding" from the user's perspective

Observed in the wild

Plugin: openclaw-remnic v9.3.82 OpenClaw: 2026.4.27 Model: ollama/glm-5.1:cloud

The plugin registers memory_search and memory_get via buildMemorySearchTool() and buildMemoryGetTool(). Both return objects with parameters: Type2.Object({...}) (TypeBox @sinclair/[email protected]).

Every agent turn produces:

plugin tool is malformed (openclaw-remnic): memory_search missing parameters object
plugin tool is malformed (openclaw-remnic): memory_get missing parameters object

Other tools from the same plugin (e.g., continuity_audit_generate, store_episode) that also use TypeBox Type.Object() inline in their registration work fine. The difference: the memory_search/memory_get tools store their schema in a module-level var (MemorySearchInputSchema, MemoryGetInputSchema) and reference it by name.

Root cause analysis

The validation in tools-Dt0Yx7_E.js:

function isRecord(value) {
    return Boolean(value && typeof value === "object" && !Array.isArray(value));
}

function describeMalformedPluginTool(tool) {
    if (!isRecord(tool)) return "tool must be an object";
    const name = readPluginToolName(tool);
    if (!name) return "missing non-empty name";
    if (typeof tool.execute !== "function") return `${name} missing execute function`;
    if (!isRecord(tool.parameters)) return `${name} missing parameters object`;
}

The tool object returned by buildMemorySearchTool:

{
    name: "memory_search",
    description: "Search Remnic memories for the OpenClaw active-memory surface.",
    parameters: MemorySearchInputSchema,  // TypeBox Type2.Object({query: Type2.String(), ...})
    execute: async function(...) { ... }
}

A TypeBox Type.Object() produces {type: "object", required: [...], properties: {...}} — a valid plain JS object that should pass isRecord(). Yet isRecord(tool.parameters) returns false at runtime.

Suspected cause: TypeBox version mismatch. The plugin ships @sinclair/[email protected] while OpenClaw bundles [email protected] (a different package entirely). When jiti loads the plugin in-process, there may be a resolution conflict where Type2.Object() produces a schema object that does not satisfy isRecord at validation time — possibly due to Symbol-based internal properties, class instances, or Proxies in the v1.x schema format.

The fact that other TypeBox-registered tools from the same plugin work (they use Type.Object() inline at the call site rather than referencing a module-level var) adds weight to a jiti/hoisting/resolution timing theory, though we could not definitively confirm this without adding debug logging to describeMalformedPluginTool.

Impact

  • Silent tool loss: The agent loses critical tools with no user-visible error
  • Cascading failures: Without memory tools, agents compensate with more tool calls → context overflow → stuck sessions → compaction loops
  • Recurring: The error fires on EVERY agent turn (tools are re-registered and re-validated each turn), producing 2+ error log entries per turn
  • Not model-specific: This is a registration-time bug, not adapter-specific (unlike the closed #69423 which was Anthropic-specific)

Steps to reproduce

  1. Install openclaw-remnic plugin (v9.3.82+)
  2. Configure OpenClaw with plugins.slots.memory = "openclaw-remnic" and openclaw-remnic.config.openclawToolsEnabled !== false
  3. Start an agent session
  4. Observe logs: plugin tool is malformed (openclaw-remnic): memory_search missing parameters object and same for memory_get
  5. Agent cannot use memory tools — no memory_search or memory_get available

Proposed fix (ranked by impact/effort)

1. Improve diagnostics in describeMalformedPluginTool (cheap, high value)

Log the actual value and type of tool.parameters when it fails isRecord, so developers can debug TypeBox/Schema version issues:

if (!isRecord(tool.parameters)) {
    return `${name} missing parameters object (got ${typeof tool.parameters}: ${JSON.stringify(tool.parameters)?.slice(0, 200)})`;
}

2. Accept both parameters and inputSchema (medium, high value)

Some plugin schemas use the MCP convention inputSchema instead of parameters:

const schema = tool.parameters ?? tool.inputSchema;
if (!isRecord(schema)) return `${name} missing parameters object`;

This would align with the fix pattern from #69423.

3. Add TypeBox-aware validation (medium, medium value)

TypeBox schemas carry a [Symbol.for("@sinclair/typebox/Kind")] property. If tool.parameters has this symbol, treat it as valid even if other checks fail:

function isValidToolSchema(value) {
    if (isRecord(value)) return true;
    if (value && typeof value === "object" && value[Symbol.for("@sinclair/typebox/Kind")]) return true;
    return false;
}

4. Document the parameters contract for plugin developers (cheap, medium value)

The plugin SDK docs should explicitly state that parameters must be a JSON Schema object (plain record), not a TypeBox class instance or other schema builder output that does not serialize to a plain object.

Environment

  • OpenClaw version: 2026.4.27
  • Plugin: openclaw-remnic v9.3.82 (TypeBox @sinclair/[email protected])
  • OS: Ubuntu Linux (aidevbot-cass)
  • Node.js: v24.14.0
  • Model: ollama/glm-5.1:cloud

Related issues

  • #69423 — Anthropic adapter crash on inputSchema vs parameters (closed; this issue is different — registration-time validation rejection of TypeBox schemas, not adapter crash)
  • #53408 — Tool parameters silently dropped in long sessions (different cause — model-side parameter loss, not registration validation)

extent analysis

TL;DR

The most likely fix is to improve diagnostics in describeMalformedPluginTool to log the actual value and type of tool.parameters when it fails isRecord, allowing developers to debug TypeBox/Schema version issues.

Guidance

  • Improve diagnostics in describeMalformedPluginTool by logging the actual value and type of tool.parameters when it fails isRecord.
  • Consider accepting both parameters and inputSchema to align with the fix pattern from #69423.
  • Add TypeBox-aware validation to treat tool.parameters as valid if it has the [Symbol.for("@sinclair/typebox/Kind")] property.
  • Document the parameters contract for plugin developers to explicitly state that parameters must be a JSON Schema object.

Example

if (!isRecord(tool.parameters)) {
    return `${name} missing parameters object (got ${typeof tool.parameters}: ${JSON.stringify(tool.parameters)?.slice(0, 200)})`;
}

Notes

The issue seems to be related to a TypeBox version mismatch between the plugin and OpenClaw. The proposed fixes aim to improve diagnostics and validation to handle this mismatch.

Recommendation

Apply the first proposed fix to improve diagnostics in describeMalformedPluginTool, as it is a low-effort, high-value change that can help developers debug the issue.

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 - 💡(How to fix) Fix [Bug]: Plugin TypeBox tool schemas rejected as 'missing parameters object' by describeMalformedPluginTool — memory tools silently dropped every turn [1 comments, 2 participants]