Summary
openclaw infer model run --local --model <id> --prompt <p> can abort before attempting any model call when ~/.openclaw/openclaw.json has a non-empty tools.alsoAllow.
The error is:
No callable tools remain after resolving explicit tool allowlist (tools.allow: *, lobster, llm-task)
This happens even though infer model run sets modelRun:true / disables tools intentionally. The target model and auth are valid. The same model succeeds when tools.alsoAllow is removed in a temp config.
Reproduce
-
Configure ~/.openclaw/openclaw.json with:
"tools": {
"profile": "coding",
"alsoAllow": ["lobster", "llm-task"]
}
-
Run:
openclaw infer model run --local --model openai-codex/gpt-5.5 --prompt 'reply exactly: ok' --json
Actual
The command aborts with:
No callable tools remain after resolving explicit tool allowlist (tools.allow: *, lobster, llm-task)
No provider request is made. The gateway never reaches the model call.
Expected
Because modelRun:true disables tools for this call shape, tool allowlist validation should not fail the model smoke. The command should attempt the model call and return the model response or a provider/model auth error.
Root cause
Observed in OpenClaw 2026.4.25 bundled output (file hashes will churn between builds; locations cited as observed):
runModelRun() sets modelRun:true and promptMode:"none" (capability CLI module).
- The execution attempt path propagates
disableTools: params.opts.modelRun === true.
- The selection module zeroes
toolsRaw when disableTools || modelRun is true, but then still calls buildEmptyExplicitToolAllowlistError(...) because the global tools.alsoAllow has been expanded into an explicit allowlist of the form ["*", ...alsoAllow] by the sandbox tool-policy module.
So the modelRun path intentionally disables tools, but the empty-explicit-allowlist guard still evaluates the global tool policy and fails closed.
Observed source locations (bundled)
dist/capability-cli-*.js — runModelRun()
dist/attempt-execution-*.js — propagates disableTools
dist/selection-*.js — toolsRaw zeroing + buildEmptyExplicitToolAllowlistError call
dist/sandbox-tool-policy-*.js — tools.alsoAllow → explicit allowlist expansion
Suggested fix
Skip the empty-explicit-allowlist guard when tools are intentionally disabled:
if (!params.modelRun && !params.disableTools && /* existing condition */) {
throw buildEmptyExplicitToolAllowlistError(...);
}
Alternatively, do not pass the global tool-policy block into that guard for modelRun/disableTools executions.
Impact
This breaks model/routing smoke tests and can produce false negatives during migrations.
We hit it during a gpt-5.5 routing cleanup on 2026-04-27 and initially rolled back a correct config patch because infer model run failed before making a provider call.
Workarounds
These production-path checks are unaffected:
openclaw cron run <id>
openclaw agent --agent <id> ...
A temp config that removes tools.alsoAllow also allows the same model/auth combo to succeed.
Environment
- OpenClaw:
2026.4.25
- Install:
~/homebrew/lib/node_modules/openclaw
- macOS: Darwin
25.3.0
Summary
openclaw infer model run --local --model <id> --prompt <p>can abort before attempting any model call when~/.openclaw/openclaw.jsonhas a non-emptytools.alsoAllow.The error is:
This happens even though
infer model runsetsmodelRun:true/ disables tools intentionally. The target model and auth are valid. The same model succeeds whentools.alsoAllowis removed in a temp config.Reproduce
Configure
~/.openclaw/openclaw.jsonwith:Run:
openclaw infer model run --local --model openai-codex/gpt-5.5 --prompt 'reply exactly: ok' --jsonActual
The command aborts with:
No provider request is made. The gateway never reaches the model call.
Expected
Because
modelRun:truedisables tools for this call shape, tool allowlist validation should not fail the model smoke. The command should attempt the model call and return the model response or a provider/model auth error.Root cause
Observed in OpenClaw 2026.4.25 bundled output (file hashes will churn between builds; locations cited as observed):
runModelRun()setsmodelRun:trueandpromptMode:"none"(capability CLI module).disableTools: params.opts.modelRun === true.toolsRawwhendisableTools || modelRunis true, but then still callsbuildEmptyExplicitToolAllowlistError(...)because the globaltools.alsoAllowhas been expanded into an explicit allowlist of the form["*", ...alsoAllow]by the sandbox tool-policy module.So the
modelRunpath intentionally disables tools, but the empty-explicit-allowlist guard still evaluates the global tool policy and fails closed.Observed source locations (bundled)
dist/capability-cli-*.js—runModelRun()dist/attempt-execution-*.js— propagatesdisableToolsdist/selection-*.js—toolsRawzeroing +buildEmptyExplicitToolAllowlistErrorcalldist/sandbox-tool-policy-*.js—tools.alsoAllow→ explicit allowlist expansionSuggested fix
Skip the empty-explicit-allowlist guard when tools are intentionally disabled:
Alternatively, do not pass the global tool-policy block into that guard for
modelRun/disableToolsexecutions.Impact
This breaks model/routing smoke tests and can produce false negatives during migrations.
We hit it during a
gpt-5.5routing cleanup on 2026-04-27 and initially rolled back a correct config patch becauseinfer model runfailed before making a provider call.Workarounds
These production-path checks are unaffected:
openclaw cron run <id>openclaw agent --agent <id> ...A temp config that removes
tools.alsoAllowalso allows the same model/auth combo to succeed.Environment
2026.4.25~/homebrew/lib/node_modules/openclaw25.3.0