agalwood/Motrix · error · AppError

PluginManifestInvalid

PluginManifestInvalid

Error message

plugin.command.schema_compile_failed: ${cmd.id}

What it means

Thrown at plugin install time by SchemaCache.installCommandSchemas when Ajv.compile throws on a command's argsSchema or resultSchema. The host compiles both schemas for every public command before the plugin is usable, so a malformed JSON Schema aborts installation with ErrorCode.PluginManifestInvalid. The original Ajv message is attached as the third AppError argument for diagnosis.

Source

Thrown at src/core/plugin/commands/schema-cache.ts:62

    const compiled = new Map<string, CompiledPair>()
    for (const cmd of cmds) {
      if (
        cmd.public !== true ||
        cmd.argsSchema === undefined ||
        cmd.resultSchema === undefined
      ) {
        continue
      }
      let args: ValidateFunction
      let result: ValidateFunction
      try {
        // Ajv typings demand AnySchema; the manifest layer passes us raw
        // JSON which we have not yet validated, so we widen here and rely
        // on Ajv to throw on malformed input (caught below).
        args = this.ajv.compile(cmd.argsSchema as AnySchema)
        result = this.ajv.compile(cmd.resultSchema as AnySchema)
      } catch (cause) {
        throw new AppError(
          ErrorCode.PluginManifestInvalid,
          `plugin.command.schema_compile_failed: ${cmd.id}`,
          cause instanceof Error ? cause.message : String(cause)
        )
      }
      compiled.set(cmd.id, { args, result })
    }
    this.byPlugin.set(pluginId, compiled)
  }

  validateArgs(pluginId: string, commandId: string, args: unknown): void {
    const pair = this.byPlugin.get(pluginId)?.get(commandId)
    if (!pair) {
      throw new AppError(
        ErrorCode.PluginRuntimeFault,
        'plugin.command.not_public'
      )
    }

View on GitHub (pinned to 1a708ee577)

Solutions

  1. Read the attached cause message (third AppError arg) — Ajv names the offending keyword and path.
  2. Validate the schema against a JSON-Schema meta-schema or ajv.compile it in isolation during development to catch the error before install.
  3. Align the schema with JSON-Schema draft-07 (the Ajv default) and avoid keywords Ajv strict mode flags.
  4. If the command should not be host-validated, set public:false (or omit it) so it is skipped — but then it cannot be invoked cross-plugin.

Example fix

// before
{ id: "acme.f.run", public: true,
  argsSchema: { typee: "object" },
  resultSchema: { type: "object" } }

// after
{ id: "acme.f.run", public: true,
  argsSchema: { type: "object", properties: {} },
  resultSchema: { type: "object", properties: {} } }
Defensive patterns

Strategy: validation

Validate before calling

import Ajv from 'ajv'
const ajv = new Ajv({ strict: true, useDefaults: false })
function schemaCompiles(s: unknown): boolean { try { ajv.compile(s as any); return true } catch { return false } }

Try / catch

try { schemaCache.installCommandSchemas(pluginId, cmds) }
catch (e) { if (e.message.startsWith('plugin.command.schema_compile_failed')) { /* fix schema from e cause text */ } else throw e }

Prevention

When it happens

Trigger: A public command (public:true) whose argsSchema or resultSchema is not a valid JSON Schema digestible by Ajv in strict mode — e.g. a $ref that resolves nowhere, an unknown keyword under strict:true, a schema that is not an object (bare string used incorrectly), or a draft-incompatible construct.

Common situations: Hand-written manifests with typos in keywords ("typee":"string"), schemas copy-pasted from a different JSON-Schema draft, use of ajv-keywords/formats without registering them, or $ref targets that were renamed. Ajv strict mode (set on the cache at schema-cache.ts:33-37) also rejects many schemas that other validators accept.

Related errors


AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12). Data as JSON: /api/errors/424d2b1befb75ca1. Report an issue: GitHub.