The docs told users to run the invocation unpinned:
Verified live in this environment. Wrote the solution to /workspace/solution.md.
Key evidence gathered:
| Check | Result |
|---|---|
npx -y @redocly/cli@2.53.3 preview-docs |
Prints openapi <command> help, no server |
npx -y @redocly/cli@^1.25.0 --version |
1.34.20 |
timeout 60 npx -y @redocly/cli@^1.25.0 preview-docs openapi.yaml --port 18766 |
Logs Preview server running at http://<ip-address>:18766, exit 124 |
ss -ltnp \| grep 18766 after timeout |
port free |
@redocly/cli to 1.x for preview-docsThe docs told users to run the invocation unpinned:
npx @redocly/cli preview-docs <spec>
npx with no version resolves to the latest published release. Redocly CLI 2.x
(2.53.3) removed the top-level preview-docs command and reorganized the CLI
around an openapi command group (stats, lint, bundle, split, ...). The
documented command exits with top-level help / "Unknown arguments" instead of
starting a server.
The repo already locks the working major in tests/package.json
(devDependencies), so the docs were the only thing drifting from CI.
Use the repo-locked major range. @^1.25.0 forces the 1.x line (resolves to
1.34.20), which still ships preview-docs.
# Before (broken once npx pulled 2.x)
npx @redocly/cli preview-docs <spec>
# After (pinned to the repo-locked 1.x major)
npx -y @redocly/cli@^1.25.0 preview-docs <spec>
Add one line near the command:
> `preview-docs` only exists in Redocly CLI 1.x — the `@^1.25.0` pin keeps the
> invocation on the version this repo tests with. If port 8080 is taken, pass
> `--port <port>` (e.g. `--port 8081`).
Keep the docs' version reference in sync with tests/package.json
("@redocly/cli": "^1.25.0").
# 1. 2.x no longer has the command
npx -y @redocly/cli@2.53.3 --version # -> 2.53.3
npx -y @redocly/cli@2.53.3 preview-docs openapi.yaml # -> openapi <command> help
# 2. pinned version
npx -y @redocly/cli@^1.25.0 --version # -> 1.34.20
# 3. live server check (redirect, don't pipe to head)
timeout 60 npx -y @redocly/cli@^1.25.0 preview-docs openapi.yaml --port 18766 \
> pinned.log 2>&1
echo "exit=$?" # -> exit=124
grep "Preview server running" pinned.log
# 4. port released after timeout
ss -ltnp | grep 18766 || echo "port 18766 free after timeout"
exit=124 (timeout killed a live process) plus the "Preview server running" line
is the success signal.
headPiping into head can leave the server child alive holding the port, causing
EADDRINUSE on retest. Check before blaming the repo:
ss -ltnp | grep <port> # existing listener?
fuser -k <port>/tcp 2>/dev/null # free a squatted port
pgrep -af preview-docs # orphaned servers
Always verify with a timeout and a redirected log, not a pipe to head.
# Evidence - Problem class: redocly-preview-docs-command-removed-major-bump - Model: openrouter/deepseek/deepseek-v4.1-flash - Solved: 2026-09-21T23:57:04.909Z - Verification: solution produced by pi in sandbox; see signatures.json
{"description": "Docs telling users to run `npx @redocly/cli preview-docs` broke verbatim (Unknown arguments) after redocly CLI 2.x (2.53.3) removed the preview-docs command. Fix: pin the invocation to the repo-locked major already declared in tests/package.json devDependencies: npx -y @redocly/cli@^1.25.0 preview-docs <spec> - the @^range forces the 1.x line (verified live: --version 1.34.20, preview server starts). Add a one-line doc note explaining the pin + --port escape hatch. Verify BEFORE editing: run the pinned command with --port and a timeout; exit 124 = live server killed by timeout = works. Beware: piping the preview command into head leaves a child server alive that squats the port (EADDRINUSE on retest); check listeners before blaming the repo.", "environment": "", "language": "", "model": "openrouter/deepseek/deepseek-v4.1-flash", "problem_class": "redocly-preview-docs-command-removed-major-bump", "provider": "openrouter", "solved_at": "2026-09-21T23:57:04.909Z", "version": ""}