nanocoai/nanoclaw · error
session_mode 'per-thread' requires honored thread ids, but t
Error message
session_mode 'per-thread' requires honored thread ids, but this wiring's thread policy resolves off ${explicit ? `(explicit threads=false)` : `(threads is NULL and channel '${key}' declares threads: false for its ${mg.is_group === 1 ? 'group' : 'dm'} context)`} — set --threads true, or keep session_mode 'shared' What it means
plugin.json failed JSON.parse; the parser's message is chained as the cause. Syntax errors (trailing commas, comments, unquoted keys) are the usual culprits since JSON does not tolerate them.
Source
Thrown at src/channels/channel-defaults.ts:190
// per-thread sessions structurally require honored thread ids — reject the
// incoherent combination rather than storing it. Creation paths that resolve
// through the declaration derive threads=1 from sessionMode 'per-thread'
// (resolveWiringDefaults), so only explicit flags can reach this: an
// explicit threads=false, or NULL-inherit on a context whose declared
// `threads` is false. Undeclared (stale) adapters stay lenient on the
// inherit arm, same as the mention checks below.
if (w.session_mode === 'per-thread') {
const key = mg.instance ?? mg.channel_type;
const explicit = w.threads !== undefined && w.threads !== null;
const honored = explicit
? w.threads !== 0 && w.threads !== false
: !hasDeclaredChannelDefaults(key, mg.channel_type) ||
(mg.is_group === 1
? getChannelDefaults(key, mg.channel_type).group
: getChannelDefaults(key, mg.channel_type).dm
).threads;
if (!honored) {
throw new Error(
`session_mode 'per-thread' requires honored thread ids, but this wiring's thread policy resolves off ` +
(explicit
? `(explicit threads=false)`
: `(threads is NULL and channel '${key}' declares threads: false for its ${mg.is_group === 1 ? 'group' : 'dm'} context)`) +
` — set --threads true, or keep session_mode 'shared'`,
);
}
}
if (w.engage_mode !== 'mention' && w.engage_mode !== 'mention-sticky') return;
const channelKey = mg.instance ?? mg.channel_type;
if (!hasDeclaredChannelDefaults(channelKey, mg.channel_type)) return;
const decl = getChannelDefaults(channelKey, mg.channel_type);
if (decl.mentions === 'never') {
throw new Error(
`engage_mode '${w.engage_mode}' can never engage on channel '${channelKey}' — its adapter declares mentions: 'never' (no mention signal is emitted; use --engage-mode pattern)`,View on GitHub (pinned to 294ef2aee8)
Solutions
- Run the file through a JSON validator or 'jq . plugin.json' to locate the syntax error
- Remove comments and trailing commas; quote all keys and string values
- Resolve any leftover merge-conflict markers
Example fix
// before
{ "name": "foo", } // trailing comma + comment
// after
{ "name": "foo" } Defensive patterns
Strategy: validation
Validate before calling
try { JSON.parse(fs.readFileSync(manifestPath, 'utf-8')); } catch (e) {
// surface the syntax error to the author before calling parseTemplate
} Try / catch
try { parseTemplate(dir); } catch (e) { if (e instanceof Error && e.message.includes('is not valid JSON')) { /* re-run editor/validator, show e.cause position */ } else throw e; } Prevention
- Lint plugin.json with jq or a JSON schema validator in CI
- Use strict-JSON editors that reject comments and trailing commas
When it happens
Trigger: plugin.json with a trailing comma, // or /* */ comments, single-quoted strings, unquoted keys, or an unterminated string — any JSON syntax error.
Common situations: Hand-editing the manifest and pasting from JS/JSON5 examples; editor auto-format inserting comments; merge conflict markers left in the file.
Related errors
- ${settingsFile} hooks must be a JSON object
- engage_mode 'pattern' requires --engage-pattern (use "." to
- ${flag} must be valid JSON
- bad request shape
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/c5a96c27bcd12d33.
Report an issue: GitHub.