fix: catch Mintlify accordion parse hazards

This commit is contained in:
Peter Steinberger
2026-04-23 19:04:35 +01:00
parent 43c5650475
commit 802646e004
4 changed files with 188 additions and 141 deletions

View File

@@ -630,12 +630,16 @@ Quick answers plus deeper troubleshooting for real-world setups (local dev, VPS,
</Accordion>
</AccordionGroup>
<a id="why-am-i-seeing-http-429-ratelimiterror-from-anthropic"></a>
<Accordion title="Why am I seeing HTTP 429 rate_limit_error from Anthropic?">
That means your **Anthropic quota/rate limit** is exhausted for the current window. If you
use **Claude CLI**, wait for the window to reset or upgrade your plan. If you
use an **Anthropic API key**, check the Anthropic Console
for usage/billing and raise limits as needed.
<AccordionGroup>
<Accordion title="Why am I seeing HTTP 429 rate_limit_error from Anthropic?">
That means your **Anthropic quota/rate limit** is exhausted for the current window. If you
use **Claude CLI**, wait for the window to reset or upgrade your plan. If you
use an **Anthropic API key**, check the Anthropic Console
for usage/billing and raise limits as needed.
If the message is specifically:
`Extra usage is required for long context requests`, the request is trying to use

View File

@@ -268,120 +268,120 @@ flowchart TD
- [/automation/cron-jobs#troubleshooting](/automation/cron-jobs#troubleshooting)
- [/gateway/heartbeat](/gateway/heartbeat)
</Accordion>
</Accordion>
<Accordion title="Node is paired but tool fails camera canvas screen exec">
```bash
openclaw status
openclaw gateway status
openclaw nodes status
openclaw nodes describe --node <idOrNameOrIp>
openclaw logs --follow
```
<Accordion title="Node is paired but tool fails camera canvas screen exec">
```bash
openclaw status
openclaw gateway status
openclaw nodes status
openclaw nodes describe --node <idOrNameOrIp>
openclaw logs --follow
```
Good output looks like:
Good output looks like:
- Node is listed as connected and paired for role `node`.
- Capability exists for the command you are invoking.
- Permission state is granted for the tool.
- Node is listed as connected and paired for role `node`.
- Capability exists for the command you are invoking.
- Permission state is granted for the tool.
Common log signatures:
Common log signatures:
- `NODE_BACKGROUND_UNAVAILABLE` → bring node app to foreground.
- `*_PERMISSION_REQUIRED` → OS permission was denied/missing.
- `SYSTEM_RUN_DENIED: approval required` → exec approval is pending.
- `SYSTEM_RUN_DENIED: allowlist miss` → command not on exec allowlist.
- `NODE_BACKGROUND_UNAVAILABLE` → bring node app to foreground.
- `*_PERMISSION_REQUIRED` → OS permission was denied/missing.
- `SYSTEM_RUN_DENIED: approval required` → exec approval is pending.
- `SYSTEM_RUN_DENIED: allowlist miss` → command not on exec allowlist.
Deep pages:
Deep pages:
- [/gateway/troubleshooting#node-paired-tool-fails](/gateway/troubleshooting#node-paired-tool-fails)
- [/nodes/troubleshooting](/nodes/troubleshooting)
- [/tools/exec-approvals](/tools/exec-approvals)
- [/gateway/troubleshooting#node-paired-tool-fails](/gateway/troubleshooting#node-paired-tool-fails)
- [/nodes/troubleshooting](/nodes/troubleshooting)
- [/tools/exec-approvals](/tools/exec-approvals)
</Accordion>
</Accordion>
<Accordion title="Exec suddenly asks for approval">
```bash
openclaw config get tools.exec.host
openclaw config get tools.exec.security
openclaw config get tools.exec.ask
openclaw gateway restart
```
<Accordion title="Exec suddenly asks for approval">
```bash
openclaw config get tools.exec.host
openclaw config get tools.exec.security
openclaw config get tools.exec.ask
openclaw gateway restart
```
What changed:
What changed:
- If `tools.exec.host` is unset, the default is `auto`.
- `host=auto` resolves to `sandbox` when a sandbox runtime is active, `gateway` otherwise.
- `host=auto` is routing only; the no-prompt "YOLO" behavior comes from `security=full` plus `ask=off` on gateway/node.
- On `gateway` and `node`, unset `tools.exec.security` defaults to `full`.
- Unset `tools.exec.ask` defaults to `off`.
- Result: if you are seeing approvals, some host-local or per-session policy tightened exec away from the current defaults.
- If `tools.exec.host` is unset, the default is `auto`.
- `host=auto` resolves to `sandbox` when a sandbox runtime is active, `gateway` otherwise.
- `host=auto` is routing only; the no-prompt "YOLO" behavior comes from `security=full` plus `ask=off` on gateway/node.
- On `gateway` and `node`, unset `tools.exec.security` defaults to `full`.
- Unset `tools.exec.ask` defaults to `off`.
- Result: if you are seeing approvals, some host-local or per-session policy tightened exec away from the current defaults.
Restore current default no-approval behavior:
Restore current default no-approval behavior:
```bash
openclaw config set tools.exec.host gateway
openclaw config set tools.exec.security full
openclaw config set tools.exec.ask off
openclaw gateway restart
```
```bash
openclaw config set tools.exec.host gateway
openclaw config set tools.exec.security full
openclaw config set tools.exec.ask off
openclaw gateway restart
```
Safer alternatives:
Safer alternatives:
- Set only `tools.exec.host=gateway` if you just want stable host routing.
- Use `security=allowlist` with `ask=on-miss` if you want host exec but still want review on allowlist misses.
- Enable sandbox mode if you want `host=auto` to resolve back to `sandbox`.
- Set only `tools.exec.host=gateway` if you just want stable host routing.
- Use `security=allowlist` with `ask=on-miss` if you want host exec but still want review on allowlist misses.
- Enable sandbox mode if you want `host=auto` to resolve back to `sandbox`.
Common log signatures:
Common log signatures:
- `Approval required.` → command is waiting on `/approve ...`.
- `SYSTEM_RUN_DENIED: approval required` → node-host exec approval is pending.
- `exec host=sandbox requires a sandbox runtime for this session` → implicit/explicit sandbox selection but sandbox mode is off.
- `Approval required.` → command is waiting on `/approve ...`.
- `SYSTEM_RUN_DENIED: approval required` → node-host exec approval is pending.
- `exec host=sandbox requires a sandbox runtime for this session` → implicit/explicit sandbox selection but sandbox mode is off.
Deep pages:
Deep pages:
- [/tools/exec](/tools/exec)
- [/tools/exec-approvals](/tools/exec-approvals)
- [/gateway/security#what-the-audit-checks-high-level](/gateway/security#what-the-audit-checks-high-level)
- [/tools/exec](/tools/exec)
- [/tools/exec-approvals](/tools/exec-approvals)
- [/gateway/security#what-the-audit-checks-high-level](/gateway/security#what-the-audit-checks-high-level)
</Accordion>
</Accordion>
<Accordion title="Browser tool fails">
```bash
openclaw status
openclaw gateway status
openclaw browser status
openclaw logs --follow
openclaw doctor
```
<Accordion title="Browser tool fails">
```bash
openclaw status
openclaw gateway status
openclaw browser status
openclaw logs --follow
openclaw doctor
```
Good output looks like:
Good output looks like:
- Browser status shows `running: true` and a chosen browser/profile.
- `openclaw` starts, or `user` can see local Chrome tabs.
- Browser status shows `running: true` and a chosen browser/profile.
- `openclaw` starts, or `user` can see local Chrome tabs.
Common log signatures:
Common log signatures:
- `unknown command "browser"` or `unknown command 'browser'` → `plugins.allow` is set and does not include `browser`.
- `Failed to start Chrome CDP on port` → local browser launch failed.
- `browser.executablePath not found` → configured binary path is wrong.
- `browser.cdpUrl must be http(s) or ws(s)` → the configured CDP URL uses an unsupported scheme.
- `browser.cdpUrl has invalid port` → the configured CDP URL has a bad or out-of-range port.
- `No Chrome tabs found for profile="user"` → the Chrome MCP attach profile has no open local Chrome tabs.
- `Remote CDP for profile "<name>" is not reachable` → the configured remote CDP endpoint is not reachable from this host.
- `Browser attachOnly is enabled ... not reachable` or `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only profile has no live CDP target.
- stale viewport / dark-mode / locale / offline overrides on attach-only or remote CDP profiles → run `openclaw browser stop --browser-profile <name>` to close the active control session and release emulation state without restarting the gateway.
- `unknown command "browser"` or `unknown command 'browser'` → `plugins.allow` is set and does not include `browser`.
- `Failed to start Chrome CDP on port` → local browser launch failed.
- `browser.executablePath not found` → configured binary path is wrong.
- `browser.cdpUrl must be http(s) or ws(s)` → the configured CDP URL uses an unsupported scheme.
- `browser.cdpUrl has invalid port` → the configured CDP URL has a bad or out-of-range port.
- `No Chrome tabs found for profile="user"` → the Chrome MCP attach profile has no open local Chrome tabs.
- `Remote CDP for profile "<name>" is not reachable` → the configured remote CDP endpoint is not reachable from this host.
- `Browser attachOnly is enabled ... not reachable` or `Browser attachOnly is enabled and CDP websocket ... is not reachable` → attach-only profile has no live CDP target.
- stale viewport / dark-mode / locale / offline overrides on attach-only or remote CDP profiles → run `openclaw browser stop --browser-profile <name>` to close the active control session and release emulation state without restarting the gateway.
Deep pages:
Deep pages:
- [/gateway/troubleshooting#browser-tool-fails](/gateway/troubleshooting#browser-tool-fails)
- [/tools/browser#missing-browser-command-or-tool](/tools/browser#missing-browser-command-or-tool)
- [/tools/browser-linux-troubleshooting](/tools/browser-linux-troubleshooting)
- [/tools/browser-wsl2-windows-remote-cdp-troubleshooting](/tools/browser-wsl2-windows-remote-cdp-troubleshooting)
- [/gateway/troubleshooting#browser-tool-fails](/gateway/troubleshooting#browser-tool-fails)
- [/tools/browser#missing-browser-command-or-tool](/tools/browser#missing-browser-command-or-tool)
- [/tools/browser-linux-troubleshooting](/tools/browser-linux-troubleshooting)
- [/tools/browser-wsl2-windows-remote-cdp-troubleshooting](/tools/browser-wsl2-windows-remote-cdp-troubleshooting)
</Accordion>
</Accordion>
</AccordionGroup>
</AccordionGroup>
## Related

View File

@@ -304,73 +304,65 @@ allowlist entries for their non-stdin workflows. For `grep` in safe-bin mode,
provide the pattern with `-e`/`--regexp`; positional pattern form is rejected
so file operands cannot be smuggled as ambiguous positionals.
<AccordionGroup>
<Accordion title="Argv validation and denied flags">
Validation is deterministic from argv shape only (no host filesystem
existence checks), which prevents file-existence oracle behavior from
allow/deny differences. File-oriented options are denied for default safe
bins; long options are validated fail-closed (unknown flags and ambiguous
abbreviations are rejected).
### Argv validation and denied flags
Denied flags by safe-bin profile:
Validation is deterministic from argv shape only (no host filesystem existence
checks), which prevents file-existence oracle behavior from allow/deny
differences. File-oriented options are denied for default safe bins; long
options are validated fail-closed (unknown flags and ambiguous abbreviations are
rejected).
[//]: # "SAFE_BIN_DENIED_FLAGS:START"
Denied flags by safe-bin profile:
[//]: # "SAFE_BIN_DENIED_FLAGS:START"
- `grep`: `--dereference-recursive`, `--directories`, `--exclude-from`, `--file`, `--recursive`, `-R`, `-d`, `-f`, `-r`
- `jq`: `--argfile`, `--from-file`, `--library-path`, `--rawfile`, `--slurpfile`, `-L`, `-f`
- `sort`: `--compress-program`, `--files0-from`, `--output`, `--random-source`, `--temporary-directory`, `-T`, `-o`
- `wc`: `--files0-from`
[//]: # "SAFE_BIN_DENIED_FLAGS:END"
[//]: # "SAFE_BIN_DENIED_FLAGS:END"
Safe bins also force argv tokens to be treated as **literal text** at
execution time (no globbing and no `$VARS` expansion) for stdin-only
segments, so patterns like `*` or `$HOME/...` cannot be used to smuggle
file reads.
Safe bins also force argv tokens to be treated as **literal text** at execution
time (no globbing and no `$VARS` expansion) for stdin-only segments, so patterns
like `*` or `$HOME/...` cannot be used to smuggle file reads.
</Accordion>
### Trusted binary directories
<Accordion title="Trusted binary directories">
Safe bins must resolve from trusted binary directories (system defaults
plus optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never
auto-trusted. Default trusted directories are intentionally minimal:
`/bin`, `/usr/bin`. If your safe-bin executable lives in
package-manager/user paths (for example `/opt/homebrew/bin`,
`/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them explicitly to
`tools.exec.safeBinTrustedDirs`.
</Accordion>
Safe bins must resolve from trusted binary directories (system defaults plus
optional `tools.exec.safeBinTrustedDirs`). `PATH` entries are never auto-trusted.
Default trusted directories are intentionally minimal: `/bin`, `/usr/bin`. If
your safe-bin executable lives in package-manager/user paths (for example
`/opt/homebrew/bin`, `/usr/local/bin`, `/opt/local/bin`, `/snap/bin`), add them
explicitly to `tools.exec.safeBinTrustedDirs`.
<Accordion title="Shell chaining, wrappers, and multiplexers">
Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment
satisfies the allowlist (including safe bins or skill auto-allow).
Redirections remain unsupported in allowlist mode. Command substitution
(`$()` / backticks) is rejected during allowlist parsing, including inside
double quotes; use single quotes if you need literal `$()` text.
### Shell chaining, wrappers, and multiplexers
On macOS companion-app approvals, raw shell text containing shell control
or expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`,
`)`) is treated as an allowlist miss unless the shell binary itself is
allowlisted.
Shell chaining (`&&`, `||`, `;`) is allowed when every top-level segment
satisfies the allowlist (including safe bins or skill auto-allow). Redirections
remain unsupported in allowlist mode. Command substitution (`$()` / backticks) is
rejected during allowlist parsing, including inside double quotes; use single
quotes if you need literal `$()` text.
For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env
overrides are reduced to a small explicit allowlist (`TERM`, `LANG`,
`LC_*`, `COLORTERM`, `NO_COLOR`, `FORCE_COLOR`).
On macOS companion-app approvals, raw shell text containing shell control or
expansion syntax (`&&`, `||`, `;`, `|`, `` ` ``, `$`, `<`, `>`, `(`, `)`) is
treated as an allowlist miss unless the shell binary itself is allowlisted.
For `allow-always` decisions in allowlist mode, known dispatch wrappers
(`env`, `nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable
path instead of the wrapper path. Shell multiplexers (`busybox`, `toybox`)
are unwrapped for shell applets (`sh`, `ash`, etc.) the same way. If a
wrapper or multiplexer cannot be safely unwrapped, no allowlist entry is
persisted automatically.
For shell wrappers (`bash|sh|zsh ... -c/-lc`), request-scoped env overrides are
reduced to a small explicit allowlist (`TERM`, `LANG`, `LC_*`, `COLORTERM`,
`NO_COLOR`, `FORCE_COLOR`).
If you allowlist interpreters like `python3` or `node`, prefer
`tools.exec.strictInlineEval=true` so inline eval still requires an
explicit approval. In strict mode, `allow-always` can still persist benign
interpreter/script invocations, but inline-eval carriers are not persisted
automatically.
For `allow-always` decisions in allowlist mode, known dispatch wrappers (`env`,
`nice`, `nohup`, `stdbuf`, `timeout`) persist the inner executable path instead
of the wrapper path. Shell multiplexers (`busybox`, `toybox`) are unwrapped for
shell applets (`sh`, `ash`, etc.) the same way. If a wrapper or multiplexer
cannot be safely unwrapped, no allowlist entry is persisted automatically.
</Accordion>
</AccordionGroup>
If you allowlist interpreters like `python3` or `node`, prefer
`tools.exec.strictInlineEval=true` so inline eval still requires an explicit
approval. In strict mode, `allow-always` can still persist benign
interpreter/script invocations, but inline-eval carriers are not persisted
automatically.
### Safe bins versus allowlist

View File

@@ -119,8 +119,58 @@ function formatMdxError(filePath, error) {
};
}
function checkMintlifyMdxStructure(filePath, raw) {
const errors = [];
const lines = stripFrontmatter(raw).split(/\r?\n/u);
const accordionStack = [];
let inCodeFence = false;
for (let index = 0; index < lines.length; index += 1) {
const line = lines[index];
if (/^\s*(```|~~~)/u.test(line)) {
inCodeFence = !inCodeFence;
continue;
}
if (inCodeFence) {
continue;
}
const openAccordion = line.match(/^(\s*)<Accordion\b/u);
if (openAccordion) {
accordionStack.push({
indent: openAccordion[1].length,
line: index + 1,
});
continue;
}
const closeAccordion = line.match(/^(\s*)<\/Accordion>/u);
if (!closeAccordion) {
continue;
}
const opening = accordionStack.pop();
if (opening && closeAccordion[1].length > opening.indent) {
errors.push({
type: "mintlify-mdx",
file: filePath,
line: index + 1,
column: closeAccordion[1].length + 1,
message:
"Accordion closing tag is indented deeper than its opening tag; Mintlify can parse following markdown as nested content.",
});
}
}
return errors;
}
async function checkMdxFile(filePath) {
const raw = fs.readFileSync(filePath, "utf8");
const structureErrors = checkMintlifyMdxStructure(filePath, raw);
if (structureErrors.length > 0) {
return structureErrors;
}
const value = stripFrontmatter(raw);
await compile(
{ path: filePath, value },
@@ -129,6 +179,7 @@ async function checkMdxFile(filePath) {
jsx: false,
},
);
return [];
}
function findDocsJsonPaths(roots) {
@@ -230,7 +281,7 @@ async function main() {
for (const file of files) {
try {
await checkMdxFile(file);
errors.push(...(await checkMdxFile(file)));
} catch (error) {
errors.push(formatMdxError(file, error));
if (errors.length >= args.maxErrors) {