MemPalace/mempalace · error · WriteRoutingError

write routing scope must be 'hooks' or 'cli'

Error message

write routing scope must be 'hooks' or 'cli'

What it means

WriteRoutingError raised in MempalaceConfig's write-routing resolution (mempalace/config.py:1011) when the scope argument passed to the policy resolver is not 'hooks' or 'cli' after strip+lower normalization. The scope selects which environment variable (MEMPALACE_HOOK_WRITE_ROUTING vs MEMPALACE_CLI_WRITE_ROUTING) anchors the candidate chain, so an unknown scope has no defined semantics and is rejected before any config is read.

Source

Thrown at mempalace/config.py:1011

        2. global environment variable;
        3. legacy hook environment variable;
        4. scope-specific config value;
        5. global config value;
        6. legacy hook config value;
        7. ``direct``.

        This foundation does not change current hook or CLI behavior. The
        policy-aware consumers are introduced by follow-up PRs.
        """

        normalized_scope = str(scope).strip().lower()
        env_names = {
            "hooks": "MEMPALACE_HOOK_WRITE_ROUTING",
            "cli": "MEMPALACE_CLI_WRITE_ROUTING",
        }

        if normalized_scope not in env_names:
            raise WriteRoutingError("write routing scope must be 'hooks' or 'cli'")

        routing_config = self._file_config.get("write_routing", {})
        if routing_config is None:
            routing_config = {}

        if not isinstance(routing_config, dict):
            raise WriteRoutingError("config write_routing must be an object")

        candidates = [
            RoutingPolicyCandidate(
                env_names[normalized_scope],
                os.environ.get(env_names[normalized_scope]),
            ),
            RoutingPolicyCandidate(
                "MEMPALACE_WRITE_ROUTING",
                os.environ.get("MEMPALACE_WRITE_ROUTING"),
            ),
        ]

View on GitHub (pinned to 06cb6987f0)

Solutions

  1. Pass exactly 'hooks' or 'cli' (case-insensitive; surrounding whitespace is tolerated) to the resolution method.
  2. If adding a genuinely new write path, extend the env_names mapping in config.py rather than passing an ad-hoc scope.
  3. Search your call sites for the scope value being interpolated (rg for the method name) and fix the producer of the bad value.

Example fix

# before
policy = config.write_routing_policy("mcp")

# after
policy = config.write_routing_policy("cli")
Defensive patterns

Strategy: type-guard

Validate before calling

scope = scope.strip().lower()
assert scope in {"hooks", "cli"}, f"bad scope: {scope!r}"

Type guard

from typing import Literal
WriteScope = Literal["hooks", "cli"]

def is_write_scope(value: object) -> bool:
    return isinstance(value, str) and value.strip().lower() in {"hooks", "cli"}

Try / catch

from mempalace.config import WriteRoutingError

try:
    policy = config.write_routing_policy(scope)
except WriteRoutingError as exc:
    # surface caller-facing config error; do not retry
    raise

Prevention

When it happens

Trigger: Calling the internal write-routing resolution method with scope="mcp", scope="hook" (singular), or scope="" ; passing a non-string scope like None or 1 that str()-ifies to something outside {hooks, cli}; a new call site added during development that uses an unsanitized scope string from user input.

Common situations: Extending MemPalace with a new entry point (e.g. an MCP tool path) and passing that label as the scope; refactoring that renames scope constants; dynamic scope built from a config key or CLI arg that is misspelled.

Related errors


AI-assisted analysis of MemPalace/mempalace@06cb6987f0 (2026-08-15). Data as JSON: /api/errors/a33799672ee1f895. Report an issue: GitHub.