ruvnet/ruflo · error · Error
Key exceeds maximum nesting depth of
Error message
Key exceeds maximum nesting depth of ${MAX_NESTING_DEPTH} What it means
Thrown by setNestedValue() in config-tools.ts:105, used by the config_set tool. Keys are dotted paths ('a.b.c'); after splitting on '.', a key with more than MAX_NESTING_DEPTH = 10 segments is rejected before any object mutation. This bounds recursion and keeps the config tree from being arbitrarily deepened by a single call.
Solutions
- Flatten the key to at most 10 segments: move the deepest levels into the value ('a.b.c.d': {remaining: 'nesting'})
- Set intermediate objects in two calls — write the deep subtree as a JSON value at a shallower key
- Serialize very deep structures to a JSON string value stored at a shallow key
Example fix
// before: 11 segments
await callTool('config_set', {
key: 'integrations.github.webhooks.events.push.filters.branch.pattern',
value: 'main',
}); // throws: Key exceeds maximum nesting depth of 10
// after: store the deep subtree as a value at a shallow key
await callTool('config_set', {
key: 'integrations.github.webhooks',
value: { events: { push: { filters: { branch: { pattern: 'main' } } } } },
}); Defensive patterns
Strategy: validation
Validate before calling
const MAX_DEPTH = 10;
function isAcceptableKey(key: string): boolean {
const parts = key.split('.');
return parts.length <= MAX_DEPTH && parts.every((p) => p && !['__proto__', 'constructor', 'prototype'].includes(p));
}
if (!isAcceptableKey(key)) throw new TypeError('config key too deep or contains a reserved segment'); Prevention
- Keep config keys shallow by design — store deep subtrees as JSON values instead of long dotted paths
- If keys are generated from object paths, cap the walk depth at generation time
When it happens
Trigger: Calling config_set with a dotted key of 11+ segments, e.g. 'integrations.github.webhooks.events.push.filters.branch.pattern' — split('.') yields 11 parts and throws. The limit counts every segment including the final leaf key.
Common situations: Auto-generating keys from deep JSON paths or feature-flag hierarchies; mistaking a dotted hostname or semver string ('cdn.v2.example.com') for a shallow key; porting a deeply nested YAML config into flat dotted keys verbatim.
Related errors
- Dangerous key segment rejected
- localCompute: no adapter for graphId=
- at least one candidate is required
- candidate must ingest at least one vector
- Dual-mode config must export a workers array
AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18).
Data as JSON: /api/errors/f558213540c14252.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/mcp-tools/config-tools.ts:105
}
const DANGEROUS_KEYS = new Set(['__proto__', 'constructor', 'prototype']);
function filterDangerousKeys(obj: Record<string, unknown>): Record<string, unknown> {
const filtered: Record<string, unknown> = {};
for (const [key, value] of Object.entries(obj)) {
if (!DANGEROUS_KEYS.has(key)) {
filtered[key] = value;
}
}
return filtered;
}
function setNestedValue(obj: Record<string, unknown>, key: string, value: unknown): void {
const MAX_NESTING_DEPTH = 10;
const parts = key.split('.');
if (parts.length > MAX_NESTING_DEPTH) {
throw new Error(`Key exceeds maximum nesting depth of ${MAX_NESTING_DEPTH}`);
}
for (const part of parts) {
if (DANGEROUS_KEYS.has(part)) {
throw new Error(`Dangerous key segment rejected: ${part}`);
}
}
let current = obj;
for (let i = 0; i < parts.length - 1; i++) {
const part = parts[i];
if (!(part in current) || typeof current[part] !== 'object') {
current[part] = {};
}
current = current[part] as Record<string, unknown>;
}
current[parts[parts.length - 1]] = value;
}
export const configTools: MCPTool[] = [View on GitHub (pinned to fa13ee4ad6)