ruvnet/ruflo · error
namespace contains disallowed characters
Error message
namespace contains disallowed characters
What it means
validateIdentifier's SHELL_META check (/[;&|`$(){}[\]<>!#\\]/) runs before the traversal and charset checks, so a namespace containing any shell metacharacter fails memory_list with 'namespace contains disallowed characters' (memory-tools.ts:705). It is the #1425 anti-injection guard shared by every MCP tool that accepts an identifier. Characters not in this set (spaces, /, unicode) instead fail the later charset check with the 'invalid characters' message.
Solutions
- Replace the metacharacters with '_' or '-' in the namespace
- Slugify generated namespaces: ns.replace(/[^A-Za-z0-9_\-.:]+/g, '-')
- Check the failing value for the exact set ; & | ` $ ( ) { } [ ] < > ! # \ and remove those characters
- Run the same check in your caller before invoking the tool so errors point at your code with better context
Example fix
// before
await mcp.callTool('memory_list', { namespace: 'patterns#auth(v2)' }); // namespace contains disallowed characters
// after
await mcp.callTool('memory_list', { namespace: 'patterns-auth-v2' }); Defensive patterns
Strategy: validation
Validate before calling
const SHELL_META = /[;&|`$(){}[\]<>!#\\]/;
function stripShellMeta(ns: string): string {
return ns.split('').map(c => SHELL_META.test(c) ? '-' : c).join('');
}
// const ns = stripShellMeta(rawNs); Type guard
function hasShellMeta(ns: string): boolean {
return /[;&|`$(){}[\]<>!#\\]/.test(ns);
}
// if (hasShellMeta(ns)) ns = stripShellMeta(ns); Try / catch
try {
await memoryList({ namespace: ns });
} catch (e) {
if (e instanceof Error && e.message.includes('namespace contains disallowed characters')) {
// sanitize the metacharacters (;&|`$(){}[]<>!#\) and retry once
}
throw e;
} Prevention
- Build namespaces only from slugified, user-typed-free input
- Escape or strip shell metacharacters whenever namespaces originate from templates or shell variables
- Apply one canonical namespace policy for store, list, cleanup, and export so all tools agree
- Unit-test namespace handling with a string containing every metacharacter
When it happens
Trigger: memory_list with namespace 'patterns#v2', 'team(a)', 'a|b', 'ns$1', 'dev;prod', or any value containing ; & | ` $ ( ) { } [ ] < > ! # \ or a NUL byte.
Common situations: Punctuation-bearing namespaces produced by templates or shell interpolation; values copied from markdown headings or log lines; the same string having been accepted earlier by memory_store's laxer write-side DANGEROUS_KEY_CHARS check (which permits spaces but also rejects these metacharacters — mismatch messages confuse users).
Related errors
- Namespace contains disallowed characters
- namespace contains invalid characters (allowed…
- namespace contains path traversal
- namespace exceeds 128 characters
- Key contains disallowed characters
AI-assisted analysis of ruvnet/ruflo@9c61c86f06 (2026-08-18).
Data as JSON: /api/errors/7840fe9a0df3a831.
Report an issue: GitHub.
Appendix: source
Thrown at v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts:805
description: 'Enumerate stored memory entries (optionally filtered by namespace/tags) without semantic search. Use when native Glob is wrong because the entries are not files (they live in .swarm/memory.db). For inspection / audit / "what is in my memory" — pair with memory_search for retrieval-by-meaning.',
category: 'memory',
inputSchema: {
type: 'object',
properties: {
namespace: { type: 'string', description: 'Filter by namespace' },
limit: { type: 'number', description: 'Maximum results (default: 50)' },
offset: { type: 'number', description: 'Offset for pagination (default: 0)' },
},
},
handler: async (input) => {
await ensureInitialized();
const { listEntries } = await getMemoryFunctions();
const namespace = input.namespace as string | undefined;
const limit = (input.limit as number) || 50;
const offset = (input.offset as number) || 0;
if (namespace) { const vNs = validateIdentifier(namespace, 'namespace'); if (!vNs.valid) throw new Error(vNs.error); }
try {
const result = await listEntries({
namespace,
limit,
offset,
});
const entries = result.entries.map(e => ({
key: e.key,
namespace: e.namespace,
storedAt: e.createdAt,
updatedAt: e.updatedAt,
accessCount: e.accessCount,
hasEmbedding: e.hasEmbedding,
size: e.size,
}));
View on GitHub (pinned to 9c61c86f06)