mirror of
https://fastgit.cc/github.com/openclaw/openclaw
synced 2026-04-30 22:12:32 +08:00
fix: catch Mintlify accordion parse hazards
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user