agalwood/Motrix · error · PluginCodedError
plugin.capability.bad_args
plugin.capability.bad_args
Error message
log.${msg.method}: invalid args What it means
Thrown by CapabilityBridge.dispatchLog when logArgsSchema.safeParse(msg.args) fails. logArgsSchema is z.tuple([z.string()]).rest(z.unknown()), so the first argument MUST be a string. Tagged plugin.capability.bad_args and marshaled back to the plugin VM as a coded error.
Source
Thrown at src/core/plugin/host/capability-bridge.ts:597
* always permitted (auto-injected). When `effectivePermissions` is
* undefined, all capabilities are permitted (back-compat for tests).
*/
private permitted(capability: string): boolean {
const required = CAPABILITY_PERMISSIONS[capability]
if (!required) return true
const eff = this.opts.effectivePermissions
if (!eff) return true
return required.some((p) => eff.has(p))
}
// -------------------------------------------------------------------------
// log
// -------------------------------------------------------------------------
private dispatchLog(msg: BridgeCallMessage): void {
const parsed = logArgsSchema.safeParse(msg.args)
if (!parsed.success) {
throw new PluginCodedError(
'plugin.capability.bad_args',
`log.${msg.method}: invalid args`
)
}
const [text, ...rest] = parsed.data
const fields = rest[0] as Record<string, unknown> | undefined
const fn = (
this.log as unknown as Record<string, (m: string, f?: object) => void>
)[msg.method]
if (typeof fn !== 'function') {
throw new PluginCodedError(
'plugin.capability.unavailable',
`unknown log method: ${msg.method}`
)
}
fn.call(this.log, String(text), fields)
}
View on GitHub (pinned to 1a708ee577)
Solutions
- Make the first log argument a string message: log.info('download started', { bytes }).
- Pass structured fields only as the optional second argument.
- If migrating from a logger that accepts object-first calls, add a shim in the worker proxy that swaps the args.
Example fix
// before
log.info({ bytes: 1024 })
// after
log.info('chunk received', { bytes: 1024 }) Defensive patterns
Strategy: validation
Validate before calling
import { z } from 'zod'
const logArgsSchema = z.tuple([z.string()]).rest(z.unknown())
// Validate before forwarding to the bridge.
if (!logArgsSchema.safeParse(args).success) {
args = [String(args[0] ?? '')].concat(args.slice(1))
} Type guard
function isLogCall(args: unknown[]): args is [string, ...unknown[]] {
return typeof args[0] === 'string'
} Try / catch
try { log.info(...args) }
catch (e) {
if (e instanceof Error && e.code === 'plugin.capability.bad_args') {
log.info(String(args[0] ?? ''), args[1]) // coerce first arg to string
return
}
throw e
} Prevention
- In the worker-side log proxy, coerce the first arg with String(...) before posting the bridge message.
- Treat log as (message: string, fields?: object) and document it in the plugin typings.
- Add a unit test that log.info(object) throws bad_args to lock the contract.
When it happens
Trigger: A plugin calls log.info(/warn/error/debug/trace) with a non-string first argument — e.g. log.info({code:1}), log.info(42), log.info(undefined). The safeParse at capability-bridge.ts:595 fails and the throw at 597-600 fires.
Common situations: Plugin passes a fields object as the first arg instead of a message string; worker-side log proxy forwards args in the wrong order; plugin assumes log accepts an object-only call like pino/winston; arity mismatch after a bridge refactor.
Related errors
- plugin.capability.unavailable
- PluginRuntimeFault
- PluginManifestInvalid
- plugin.fs.task.not_available_outside_hook
- plugin.metadata.not_available_outside_hook
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/8ecbe8221124de24.
Report an issue: GitHub.