can1357/oh-my-pi · error

memory:// URL requires a namespace: memory://root or memory:

Error message

memory:// URL requires a namespace: memory://root or memory://<memory-id>

What it means

With a memory backend active, the host portion of a memory:// URL is the namespace: 'root' for the file-backed memory summary, or a mnemopi memory id. A URL with no host at all (e.g. 'memory://' or 'memory:///path') has nothing to resolve, so resolve throws and tells the caller the two accepted URL forms.

Source

Thrown at packages/coding-agent/src/internal-urls/memory-protocol.ts:299

/**
 * Protocol handler for memory:// URLs.
 * Resolves file-backed roots against the calling session cwd when provided.
 * Contextless callers fall back to the live-session registry for legacy
 * cross-session lookups.
 */
export class MemoryProtocolHandler implements ProtocolHandler {
	readonly scheme = "memory";
	readonly immutable = true;

	async resolve(url: InternalUrl, context?: ResolveContext): Promise<InternalResource> {
		const backend = memoryBackendFromContext(context);
		if (backend === "off") {
			throw new Error("Unknown protocol: memory://");
		}
		const namespace = url.rawHost || url.hostname;
		if (!namespace) {
			throw new Error("memory:// URL requires a namespace: memory://root or memory://<memory-id>");
		}

		// Mnemopi rows live in SQLite banks per session, keyed by memory id.
		// Any host other than the file-backed `root` namespace is treated as a
		// mnemopi memory id lookup. This is the read counterpart to
		// `memory_edit update` and lets agents inspect the full content of a
		// clipped recall preview before overwriting it (issue #4443).
		if (namespace !== MEMORY_NAMESPACE) {
			const mnemopiStates = mnemopiSessionStatesFromRegistry();
			const hindsightActive =
				backend === "hindsight" ||
				(mnemopiStates.length === 0 &&
					AgentRegistry.global()
						.list()
						.some(ref => ref.session?.getHindsightSessionState?.()));
			if (hindsightActive) {
				// Hindsight keeps memories server-side and exposes no
				// `memory://<id>` addressing, yet the shared `recall` tool

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the project memory summary with 'memory://root'.
  2. Read a stored mnemopi memory by id with 'memory://<memory-id>' using an id listed by recall.
  3. Fix the URL builder/prompt so the namespace is always interpolated and non-empty.

Example fix

// before
read("memory://")
// after
read("memory://root")
Defensive patterns

Strategy: validation

Validate before calling

const ns = url.rawHost || url.hostname;
if (!ns) throw new Error(`Use memory://root or memory://<memory-id>, got: ${url.href}`);

Type guard

function hasNamespace(url: InternalUrl): boolean {
  return Boolean(url.rawHost || url.hostname);
}

Try / catch

try {
  return await handler.resolve(url, ctx);
} catch (err) {
  if (err instanceof Error && err.message.includes("requires a namespace")) {
    return await handler.resolve(parseInternalUrl("memory://root"), ctx);
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling MemoryProtocolHandler.resolve with an InternalUrl whose rawHost/hostname are empty — 'memory://', 'memory:///' — from a read tool call or programmatic URL construction that omitted the namespace.

Common situations: Agents emitting 'read memory://' after truncation; template strings where the id variable was empty; users typing memory:// in a path prompt without the 'root' host.

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/68b52ffaad1e74cb. Report an issue: GitHub.