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

  1. Replace the metacharacters with '_' or '-' in the namespace
  2. Slugify generated namespaces: ns.replace(/[^A-Za-z0-9_\-.:]+/g, '-')
  3. Check the failing value for the exact set ; & | ` $ ( ) { } [ ] < > ! # \ and remove those characters
  4. 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

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


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)