You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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)
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:
functionisRecord(value){returnBoolean(value&&typeofvalue==="object"&&!Array.isArray(value));}functiondescribeMalformedPluginTool(tool){if(!isRecord(tool))return"tool must be an object";constname=readPluginToolName(tool);if(!name)return"missing non-empty name";if(typeoftool.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: asyncfunction(...){ ... }}
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
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:
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.
Bug type
Behavior bug (incorrect output/state without crash)
Summary
Plugin tools that use TypeBox
Type.Object()schemas for theirparametersfield are rejected by OpenClaw'sdescribeMalformedPluginToolvalidator 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-remnicmemory plugin'smemory_searchandmemory_gettools are rejected every turn, causing:Observed in the wild
Plugin:
openclaw-remnicv9.3.82OpenClaw: 2026.4.27
Model: ollama/glm-5.1:cloud
The plugin registers
memory_searchandmemory_getviabuildMemorySearchTool()andbuildMemoryGetTool(). Both return objects withparameters: Type2.Object({...})(TypeBox@sinclair/[email protected]).Every agent turn produces:
Other tools from the same plugin (e.g.,
continuity_audit_generate,store_episode) that also use TypeBoxType.Object()inline in their registration work fine. The difference: thememory_search/memory_gettools store their schema in a module-levelvar(MemorySearchInputSchema,MemoryGetInputSchema) and reference it by name.Root cause analysis
The validation in
tools-Dt0Yx7_E.js:The tool object returned by
buildMemorySearchTool:A TypeBox
Type.Object()produces{type: "object", required: [...], properties: {...}}— a valid plain JS object that should passisRecord(). YetisRecord(tool.parameters)returnsfalseat 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 whereType2.Object()produces a schema object that does not satisfyisRecordat 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-levelvar) adds weight to a jiti/hoisting/resolution timing theory, though we could not definitively confirm this without adding debug logging todescribeMalformedPluginTool.Impact
Steps to reproduce
openclaw-remnicplugin (v9.3.82+)plugins.slots.memory = "openclaw-remnic"andopenclaw-remnic.config.openclawToolsEnabled !== falseplugin tool is malformed (openclaw-remnic): memory_search missing parameters objectand same formemory_getmemory_searchormemory_getavailableProposed fix (ranked by impact/effort)
1. Improve diagnostics in
describeMalformedPluginTool(cheap, high value)Log the actual value and type of
tool.parameterswhen it failsisRecord, so developers can debug TypeBox/Schema version issues:2. Accept both
parametersandinputSchema(medium, high value)Some plugin schemas use the MCP convention
inputSchemainstead ofparameters: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. Iftool.parametershas this symbol, treat it as valid even if other checks fail:4. Document the
parameterscontract for plugin developers (cheap, medium value)The plugin SDK docs should explicitly state that
parametersmust 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
Related issues
inputSchemavsparameters(closed; this issue is different — registration-time validation rejection of TypeBox schemas, not adapter crash)