ruvnet/ruflo · error · Error

Namespace contains disallowed characters

Error message

Namespace contains disallowed characters

What it means

Thrown by validateMemoryInput when a namespace matches the same DANGEROUS_KEY_PATTERN as keys. Namespaces partition the memory store into directories/collections and feed filesystem paths, so shell metacharacters and path-traversal sequences are rejected identically to keys. The check is symmetric with the key check (the #1884 symmetry fix).

Source

Thrown at v3/@claude-flow/cli/src/mcp-tools/memory-tools.ts:86

const DANGEROUS_KEY_CHARS = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/g;
const DANGEROUS_KEY_PATTERN = /[;&|`$(){}[\]<>!#\\\0]|\.\.[/\\]/;

function validateMemoryInput(key?: string, value?: string, query?: string, namespace?: string): void {
  if (key && key.length > MAX_KEY_LENGTH) {
    throw new Error(`Key exceeds maximum length of ${MAX_KEY_LENGTH} characters`);
  }
  if (value && value.length > MAX_VALUE_SIZE) {
    throw new Error(`Value exceeds maximum size of ${MAX_VALUE_SIZE} bytes`);
  }
  if (query && query.length > MAX_QUERY_LENGTH) {
    throw new Error(`Query exceeds maximum length of ${MAX_QUERY_LENGTH} characters`);
  }
  // Reject path traversal and shell metacharacters in keys/namespaces (#1425)
  if (key && DANGEROUS_KEY_PATTERN.test(key)) {
    throw new Error('Key contains disallowed characters');
  }
  if (namespace && DANGEROUS_KEY_PATTERN.test(namespace)) {
    throw new Error('Namespace contains disallowed characters');
  }
}

// #1884 — sanitize a key produced from arbitrary input (markdown headings,
// frontmatter names, file names) so it survives validateMemoryInput on the
// read/delete path. Replaces every dangerous char with `_`. Truncates to
// MAX_KEY_LENGTH so the bound check in validateMemoryInput also passes.
// Keep this in sync with DANGEROUS_KEY_PATTERN — they share DANGEROUS_KEY_CHARS.
function sanitizeMemoryKey(key: string): string {
  const safe = key.replace(DANGEROUS_KEY_CHARS, '_');
  return safe.length > MAX_KEY_LENGTH ? safe.slice(0, MAX_KEY_LENGTH) : safe;
}

// #1937 — minimal glob → RegExp helper for memory_import_claude exclusion
// patterns. Anchored. Supports the three operators the issue's voice-fidelity
// workflow needs:
//   `**` — any chars including path separators
//   `*`  — any chars except path separators

View on GitHub (pinned to 6b01dc5a68)

Solutions

  1. Restrict namespaces to an allowlist charset ([A-Za-z0-9._-]).
  2. Hash or slugify arbitrary namespace input before calling memory tools.
  3. Validate namespaces with the same scrubbing used for keys.
  4. Never pass raw user input as a namespace.

Example fix

// before
memory store --namespace "tenant/a;b" --key k --value v
// after
const ns = tenantId.replace(/[^A-Za-z0-9._-]/g, '_')
memory store --namespace "$ns" --key k --value v
Defensive patterns

Strategy: validation

Validate before calling

function sanitizeNamespace(ns) {
  return ns.replace(/[;&|`$(){}[\]<>!#\\\0]|\.\.[\/\\]/g, '_');
}

Type guard

function isSafeNamespace(ns: string): boolean {
  return !/[;&|`$(){}[\]<>!#\\\0]|\.\.[\/\\]/.test(ns);
}

Prevention

When it happens

Trigger: Calling any memory tool with a --namespace containing ';', '|', '$', backticks, '../', brackets, or null bytes. The regex test runs after the namespace length is implicitly acceptable (no separate namespace length cap shown).

Common situations: User/tenant IDs used as namespaces that contain slashes or special chars; LLM-generated namespace strings; path-traversal attempts targeting another namespace's data; namespaces built from file paths.

Related errors


AI-assisted analysis of ruvnet/ruflo@6b01dc5a68 (2026-08-12). Data as JSON: /api/errors/0c79a5818b6bebee. Report an issue: GitHub.