{"record":{"id":"5df19d9f09a27ea1","repo":"agalwood/Motrix","slug":"plugin-commands-not-found","errorCode":"plugin.commands.not_found","errorMessage":"command \"${commandId}\" is not registered","messagePattern":"command \"(.+?)\" is not registered","errorType":"exception","errorClass":"CommandsError","httpStatus":null,"severity":"error","filePath":"src/core/plugin/capabilities/commands.ts","lineNumber":162,"sourceCode":"\n  /**\n   * Execute a command.\n   *\n   * - Own-namespace (`commandId` starts with `${callerId}.`): dispatches to\n   *   the registered handler. Rejects with `not_found` if absent. Any error\n   *   thrown by the handler surfaces as-is.\n   * - Foreign-namespace: forwarded to the bound CrossPluginInvoker. Rejects\n   *   with `access_denied` if no invoker is bound.\n   */\n  async execute(\n    callerId: string,\n    commandId: string,\n    args: unknown\n  ): Promise<unknown> {\n    if (commandId.startsWith(`${callerId}.`)) {\n      const handler = this.handlers.get(commandId)\n      if (!handler) {\n        throw new CommandsError(\n          'plugin.commands.not_found',\n          `command \"${commandId}\" is not registered`\n        )\n      }\n      const startTs = Date.now()\n      try {\n        const result = await handler(args)\n        this.onSelfInvoke?.({\n          callerId,\n          commandId,\n          durMs: Date.now() - startTs,\n          ok: true,\n        })\n        return result\n      } catch (err) {\n        this.onSelfInvoke?.({\n          callerId,\n          commandId,","sourceCodeStart":144,"sourceCodeEnd":180,"githubUrl":"https://github.com/agalwood/Motrix/blob/1a708ee57746c434e2c67a44bbf0906a976afea4/src/core/plugin/capabilities/commands.ts#L144-L180","documentation":"Thrown by CommandsCapabilityHost.execute() when a plugin calls a command whose ID starts with its own namespace (e.g. `<callerId>.foo`) but no handler was ever registered for that exact commandId. The capability dispatches own-namespace calls directly from an in-memory handler map; a miss is a programming error, not a runtime race. The error code is `plugin.commands.not_found`.","triggerScenarios":"Calling `execute(callerId, 'myPlugin.doThing', args)` where `callerId === 'myPlugin'` but `register('myPlugin.doThing', handler)` was never called (or was disposed). Also triggered by a typo in the commandId that still matches the namespace prefix, or by attempting to invoke a command after teardown/unregister.","commonSituations":"Plugin author forgot to register the command in their activate() lifecycle; manifest declares `contributes.commands[]` with id X but the handler registers under a slightly different id; a dispose() ran during teardown and a queued callback still calls execute().","solutions":["Verify the commandId string passed to execute() byte-for-byte matches the one passed to register(); check for trailing whitespace, casing, or a missing/extra segment.","Ensure register() is called during plugin activation and that its returned CommandsRegistration has not been disposed before execute() runs.","If the command is meant to be invoked cross-plugin (foreign namespace), drop the callerId prefix so it routes through the CrossPluginInvoker path instead.","Search the plugin source for every register() call and confirm the target id is among them before invoking."],"exampleFix":"// before\nawait cmds.execute('myPlugin', 'myPlugin.runTask', {})\n// register() was never called for 'myPlugin.runTask'\n\n// after\nconst reg = cmds.register('myPlugin.runTask', async (args) => doWork(args))\nawait cmds.execute('myPlugin', 'myPlugin.runTask', {})","handlingStrategy":"validation","validationCode":"function isRegistered(cmds: CommandsCapabilityHost, id: string): boolean {\n  // expose a list/has on the host if available; otherwise track locally\n  return registeredIds.has(id)\n}\nif (!isRegistered(cmds, 'myPlugin.runTask')) {\n  throw new Error('command not registered; cannot execute')\n}","typeGuard":"function isCommandsError(e: unknown, code = 'plugin.commands.not_found'): e is CommandsError {\n  return e instanceof Error && (e as CommandsError).code === code\n}","tryCatchPattern":"try {\n  await cmds.execute(callerId, commandId, args)\n} catch (e) {\n  if (isCommandsError(e, 'plugin.commands.not_found')) {\n    // register lazily or surface a clear 'command unavailable' message\n  } else throw e\n}","preventionTips":["Track every register() id in a local Set and assert execute() targets are members.","Register all commands in activate() and dispose them only in deactivate().","Add a unit test that calls execute() for each id you registered."],"tags":["plugin","commands","registration","dispatch"],"backgroundTag":null,"analyzedSha":"1a708ee57746c434e2c67a44bbf0906a976afea4","analyzedAt":"2026-08-12T16:18:09.346Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}