Skip to content

@blockrun/clawrouter@0.12.23 destructively normalizes TOP_MODELS in injectModelsConfig(), pruning user-defined blockrun/* allowlist entries and causing plugin-induced "model not allowed" #82

@KevinkeVarson

Description

@KevinkeVarson

In ClawRouter 0.12.23, injectModelsConfig() mutates ~/.openclaw/openclaw.json and deletes user-defined agents.defaults.models entries for blockrun/* IDs not in internal TOP_MODELS.

This creates a hard contradiction:

  1. Provider catalog is broad (41+ models; currently 45 model IDs in code),
  2. Effective callable allowlist is forcibly narrowed to TOP_MODELS (16 entries).

Result: valid catalog model IDs become non-callable after startup/reload and fail with:

Model "<blockrun/model-id>" is not allowed

Environment

  • OpenClaw: 2026.3.2
  • ClawRouter: 0.12.23
  • Plugin file (relative): .openclaw/extensions/clawrouter/dist/index.js
  • Config file (relative): .openclaw/openclaw.json

User-facing impact

  • User-authored allowlist entries do not persist.
  • Effective model policy regresses to top-set policy after plugin lifecycle.
  • Error semantics imply user configuration fault while root cause is plugin-side mutation.
  • Catalog discoverability and callable policy diverge.
  • Persisted config is rewritten without user action beyond normal startup/restart.

Deterministic reproduction (copy/paste)

# 1) Add a non-top BlockRun model ID to allowlist
# ~/.openclaw/openclaw.json -> agents.defaults.models
# e.g. "blockrun/openai/gpt-5.4": {}

# 2) Restart gateway
openclaw gateway restart

# 3) Inspect effective allowlist
openclaw models status --json

# 4) Attempt to invoke the model
# Expect runtime rejection after pruning:
# Model "blockrun/openai/gpt-5.4" is not allowed

Observed log pattern:

Added 1 models to allowlist (16 total)
Smart routing enabled (blockrun/auto)
Config overwrite: ~/.openclaw/openclaw.json (...)

Root-cause proof chain (high confidence)

A) Direct destructive logic exists

In dist/index.js, function injectModelsConfig():

const topSet = new Set(TOP_MODELS.map((id) => `blockrun/${id}`));
for (const key of Object.keys(allowlist)) {
  if (key.startsWith("blockrun/") && !topSet.has(key)) {
    delete allowlist[key];
    needsWrite = true;
  }
}

This is explicit deletion of user allowlist entries outside TOP_MODELS.

B) Function is invoked during plugin registration

In same file, plugin register(api) calls:

api.registerProvider(blockrunProvider);
injectModelsConfig(api.logger);
injectAuthProfile(api.logger);

Which makes the prune behavior part of ordinary lifecycle, not an edge-case repair pass.

C) Log signatures uniquely map to this code path

The strings below appear once in code and are emitted by this function:

  • Added ${addedCount} models to allowlist (${TOP_MODELS.length} total)
  • Smart routing enabled (blockrun/auto)

These same signatures appear in runtime logs during observed reversion.

D) Version delta check confirms issue persists in latest

Compared installed package code in 0.12.13 –> 0.12.23:

  • injectModelsConfig() deletion behavior is unchanged.
  • TOP_MODELS remains 16.
  • Broad catalog remains (45 IDs in code path).

Root-cause localization

  • File: dist/index.js
  • Function: injectModelsConfig(logger)
  • Behavior: destructive normalization of agents.defaults.models to curated TOP_MODELS

Expected behavior

If a model ID is valid in provider catalog and explicitly present in agents.defaults.models, it should remain callable unless removed by user/admin policy.


Request to maintainers

Please clarify whether this behavior is intentional policy.

If intentional:

  • expose as explicit opt-in config (e.g., enforceTopModelsAllowlist: true|false), default off,
  • document that direct model IDs outside curated set are not supported.

If unintentional:

  • switch from destructive prune to additive merge (preserve user-defined keys, add defaults only).

Regression tests suggested

  1. User-added blockrun/* allowlist entries survive gateway restart.
  2. No plugin-driven deletion of persisted model policy unless explicit enforcement is enabled.
  3. Advertised provider model IDs are not blocked by implicit pruning.
  4. Error messaging distinguishes policy-pruned vs not-configured model states.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions