agalwood/Motrix · error · MetadataError
plugin.metadata.value_not_serializable
plugin.metadata.value_not_serializable
Error message
plugin.metadata.value_not_serializable: undefined is not JSON-serializable
What it means
The top-level value passed to the metadata set() path is strictly undefined. JSON.stringify would silently drop a top-level undefined (returning undefined), so serialize() short-circuits to an explicit, message-bearing error rather than storing nothing. This is the value===undefined branch, distinct from 113 (stringify threw) and 114 (stringify returned undefined).
Source
Thrown at src/core/plugin/capabilities/metadata.ts:68
}
}
// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------
const DEFAULT_QUOTA = 64 << 10 // 64 KB
/**
* Serialize `value` to JSON.
* Throws `plugin.metadata.value_not_serializable` when:
* - the value is top-level `undefined`
* - JSON.stringify returns undefined (e.g. a plain function)
* - JSON.stringify throws (e.g. BigInt, class with throwing toJSON)
*/
function serialize(value: unknown): string {
if (value === undefined) {
throw new MetadataError(
'plugin.metadata.value_not_serializable',
'plugin.metadata.value_not_serializable: undefined is not JSON-serializable'
)
}
let json: string | undefined
try {
json = JSON.stringify(value)
} catch {
throw new MetadataError(
'plugin.metadata.value_not_serializable',
'plugin.metadata.value_not_serializable: value cannot be serialized to JSON'
)
}
if (json === undefined) {
throw new MetadataError(
'plugin.metadata.value_not_serializable',
'plugin.metadata.value_not_serializable: value cannot be serialized to JSON'
)View on GitHub (pinned to 1a708ee577)
Solutions
- Use null (or an explicit empty marker) instead of undefined to represent absence.
- Skip the set() call entirely when the value is undefined.
- Default the value at the source with ?? null or ?? {}.
Example fix
// before await metadata.set(taskId, pluginId, key, maybeValue) // after if (maybeValue !== undefined) await metadata.set(taskId, pluginId, key, maybeValue)
Defensive patterns
Strategy: validation
Validate before calling
if (value === undefined) throw new Error('metadata value required')
await metadata.set(taskId, pluginId, key, value) Type guard
function isDefined<T>(v: T | undefined): v is T { return v !== undefined } Prevention
- Represent absence with null, not undefined, in stored values.
- Skip the set() call when the value is undefined instead of storing a marker.
- Constrain settable values to a JSONValue type so the compiler flags undefined.
When it happens
Trigger: Calling metadata.set(taskId, pluginId, key, undefined); a variable that was conditionally assigned and ended up undefined; reading a missing config field and passing it straight through.
Common situations: Plugin stores the result of an optional lookup without checking; refactor left a placeholder; TypeScript optional property accessed without nullish-coalescing.
Related errors
- plugin.storage.value_not_serializable
- IpcInvalidPayload
- taskId must be a string
- Key must be 16 bytes, got ${key.length}
- IV must be 16 bytes, got ${iv.length}
AI-assisted analysis of agalwood/Motrix@1a708ee577 (2026-08-12).
Data as JSON: /api/errors/02a2dc681597fbf1.
Report an issue: GitHub.