jackwener/OpenCLI · error · CommandExecutionError
${label} request failed: ${err?.message ?? err}
Error message
${label} request failed: ${err?.message ?? err} What it means
CommandExecutionError thrown by pypiFetch when the underlying fetch itself rejects — i.e. the request never got an HTTP response. The label identifies which call (e.g. 'pypi package <name>') failed, and the original error message is appended.
Source
Thrown at clis/pypi/utils.js:30
export function requirePackageName(value) {
const s = String(value ?? '').trim();
if (!s) throw new ArgumentError('pypi package name is required (e.g. "requests", "pandas")');
if (!PKG_NAME.test(s)) {
throw new ArgumentError(
`pypi package name "${value}" is not a valid distribution name`,
'PyPI accepts ASCII letters / digits / "._-" with no leading or trailing separator.',
);
}
return s;
}
export async function pypiFetch(url, label) {
let resp;
try {
resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
}
catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that pypi.org / pypistats.org are reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `PyPI returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'PyPI throttles unauthenticated bursts; wait a few seconds and retry.',
);
}
if (!resp.ok) {
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
}
let body;
try {View on GitHub (pinned to 49907e53dc)
Solutions
- Check basic connectivity: curl -I https://pypi.org
- Check proxy env vars (HTTP_PROXY/HTTPS_PROXY) are correct if behind a proxy
- Retry after transient network issues; add retry/backoff around CLI calls
- Verify DNS resolves pypi.org (nslookup pypi.org)
Example fix
// before
const data = await pypiFetch(url, 'pypi pkg'); // throws on network blip
// after
let data;
for (let i = 0; i < 3; i++) {
try { data = await pypiFetch(url, 'pypi pkg'); break; }
catch (e) { if (i === 2) throw e; await new Promise(r => setTimeout(r, 2 ** i * 500)); }
} Defensive patterns
Strategy: retry
Validate before calling
// pre-check reachability
const ok = await fetch('https://pypi.org/simple/', { method: 'HEAD' }).then(r => r.ok).catch(() => false);
if (!ok) throw new Error('pypi.org unreachable from this network'); Type guard
null
Try / catch
async function fetchWithRetry(url, label, tries = 3) {
for (let i = 0; ; i++) {
try { return await pypiFetch(url, label); }
catch (e) {
if (i >= tries - 1 || !/request failed/i.test(e.message)) throw e;
await new Promise(r => setTimeout(r, 2 ** i * 500));
}
}
} Prevention
- Check proxy env vars (HTTP_PROXY/HTTPS_PROXY/NO_PROXY) before running
- Prefer wired/stable networks for CI jobs hitting PyPI
- Add exponential backoff on network errors in batch scripts
When it happens
Trigger: Any pypiFetch call where DNS resolution fails, the connection is refused/times out, TLS fails, or the process lacks network access to pypi.org or pypistats.org.
Common situations: Working offline or on a flaky network; corporate firewalls blocking pypi.org; misconfigured proxy environment variables; DNS outages; IPv6-only environments.
Related errors
- FETCH_ERROR
- archive search request failed: ${error?.message || error}
- archive wayback request failed: ${error?.message || error}
- ${label} request failed: ${err?.message ?? err}
- 字幕获取失败: ${err?.message || err}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/4a8785a2e054125c.
Report an issue: GitHub.