ruvnet/ruflo · error

namespace must be a non-empty string

Error message

namespace must be a non-empty string

What it means

memory_list validates its optional namespace with the shared validateIdentifier (from cli-core validate-input.ts, wired in at memory-tools.ts:705) and throws the validator's message on failure. This variant fires when the value is truthy but not a non-empty string: the handler only casts (`input.namespace as string | undefined`), so a JSON number, array, or object reaches the validator as-is and fails the typeof check. The check runs only when namespace is truthy, so omitting it (or passing '') lists across all namespaces without error.

Source

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

    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 fa13ee4ad6)

Solutions

  1. Pass the namespace as a JSON string: { namespace: 'patterns' }
  2. Omit the namespace field entirely when you want entries from all namespaces
  3. Coerce at the call site: namespace: cfg.namespace == null ? undefined : String(cfg.namespace)
  4. Type the caller's request payload as { namespace?: string } so compile-time or schema validation catches it earlier

Example fix

// before
await mcp.callTool('memory_list', { namespace: 123 }); // number -> namespace must be a non-empty string

// after
await mcp.callTool('memory_list', { namespace: 'patterns' });
Defensive patterns

Strategy: type-guard

Validate before calling

// memory_list only skips validation for falsy namespace; ensure you pass string|undefined.
const ns = typeof args.namespace === 'string' && args.namespace.length > 0 ? args.namespace : undefined;
await mcp.callTool('memory_list', ns ? { namespace: ns } : {});

Type guard

function isNamespaceArg(v: unknown): v is string | undefined {
  return v === undefined || (typeof v === 'string' && v.length > 0);
}
// if (!isNamespaceArg(args.namespace)) throw new TypeError('namespace must be a non-empty string or omitted');

Try / catch

try {
  await memoryList({ namespace: args.namespace });
} catch (e) {
  if (e instanceof Error && e.message === 'namespace must be a non-empty string') {
    // caller sent a non-string JSON value — coerce or reject at your boundary, then retry
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling memory_list with { "namespace": 5 }, { "namespace": ["patterns"] }, or { "namespace": { "name": "patterns" } } — MCP JSON arguments are not coerced to the declared string type, so any non-string truthy JSON value produces exactly this message.

Common situations: LLM-generated tool arguments using the wrong JSON type; programmatic callers passing a numeric ID or enum where the namespace name was expected; configuration defaults that produce numbers.

Understand the failure class

Background: "Wrong argument type", "must be a string", "expected Array or Prism::Scope": TypeError and ArgumentError when a library receives a value of the wrong type — this error's family across 28 libraries.

Related errors


AI-assisted analysis of ruvnet/ruflo@fa13ee4ad6 (2026-08-18). Data as JSON: /api/errors/2125c8a7ba0898a1. Report an issue: GitHub.