jackwener/OpenCLI · error · CommandExecutionError
${label} returned HTTP ${resp.status}
Error message
${label} returned HTTP ${resp.status} What it means
gemsFetch (clis/rubygems/utils.js:68) wraps every RubyGems.org REST call. It explicitly handles 404 (EmptyResultError) and 429 (rate-limit hint), and any other non-OK status falls into this generic CommandExecutionError carrying the raw HTTP status in the message. It signals that rubygems.org answered but with an unhandled error status (e.g. 500, 503, 403).
Source
Thrown at clis/rubygems/utils.js:68
resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });
}
catch (err) {
throw new CommandExecutionError(
`${label} request failed: ${err?.message ?? err}`,
'Check that rubygems.org is reachable from this network.',
);
}
if (resp.status === 404) {
throw new EmptyResultError(label, `RubyGems returned 404 for ${url}.`);
}
if (resp.status === 429) {
throw new CommandExecutionError(
`${label} returned HTTP 429 (rate limited)`,
'RubyGems throttles bursts; wait a few seconds and retry.',
);
}
if (!resp.ok) {
throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);
}
let body;
try {
body = await resp.json();
}
catch (err) {
throw new CommandExecutionError(`${label} returned malformed JSON: ${err?.message ?? err}`);
}
return body;
}
/** Trim "2026-03-24T20:27:42.098Z" → "2026-03-24T20:27:42Z" so timestamps share a uniform precision. */
export function trimDate(value) {
const s = String(value ?? '').trim();
if (!s) return null;
const noFrac = s.replace(/\.\d+/, '');
return noFrac.endsWith('Z') ? noFrac : `${noFrac}Z`;
}View on GitHub (pinned to 49907e53dc)
Solutions
- Re-run the command after a short delay — 5xx statuses from rubygems.org are usually transient.
- Check https://status.rubygems.org for an ongoing outage.
- If you get 403/407, check proxy/VPN configuration and that rubygems.org is reachable (curl the URL directly).
- Retry with a different network (e.g. disable corporate proxy) to rule out network interception.
- Capture the exact HTTP status in the message and consult RubyGems API docs for that status code.
Example fix
// before
await gemsFetch(`${GEMS_BASE}/gems/${name}.json`, 'rubygems gem info');
// after
try {
const info = await gemsFetch(`${GEMS_BASE}/gems/${name}.json`, 'rubygems gem info');
} catch (err) {
if (/returned HTTP 5\d\d/.test(err.message)) {
// retry with backoff or check status.rubygems.org
}
} Defensive patterns
Strategy: retry
Validate before calling
// Pre-check service health before batch calls
const health = await fetch('https://rubygems.org/api/v1/versions/rails.json');
if (!health.ok && health.status >= 500) throw new Error('rubygems.org is unhealthy; defer batch'); Type guard
function isUnhandledHttpStatus(err) {
return err instanceof Error && /returned HTTP \d{3}/.test(err.message) && !/HTTP (404|429)/.test(err.message);
} Try / catch
try {
const info = await gemsFetch(url, 'rubygems gem info');
} catch (err) {
if (/returned HTTP 5\d\d/.test(err.message)) {
await sleep(2000);
return gemsFetch(url, 'rubygems gem info'); // retry with backoff
}
throw err;
} Prevention
- Add exponential backoff + retry for 5xx in batch jobs.
- Check status.rubygems.org before large bulk runs.
- Throttle request rate to avoid triggering protective 403/5xx responses.
- Keep a custom user-agent so RubyGems can contact you instead of blocking silently.
When it happens
Trigger: Any gemsFetch call (gem info, versions, downloads, search) where the fetch succeeded but resp.ok is false and the status is neither 404 nor 429 — e.g. rubygems.org returning 5xx during an outage, a 403 from a proxy/firewall, or a 410 for removed endpoints.
Common situations: RubyGems.org incidents/degraded service; corporate proxies or VPNs intercepting requests and returning 403/502; rubygems.org temporarily blocking a user-agent or IP range; transient 502/503 from the CDN in front of rubygems.org.
Related errors
- ${label} returned HTTP ${resp.status}: ${summarizeApiError(p
- HTTP ${result.httpStatus} from /api/organizations
- coingecko derivatives returned HTTP ${resp.status}
- Ctrip flight API returned HTTP ${status || 'unknown'}
- ${label} returned HTTP ${res.status}
AI-assisted analysis of jackwener/OpenCLI@49907e53dc (2026-08-29).
Data as JSON: /api/errors/259239ef2740f608.
Report an issue: GitHub.