{"record":{"id":"74ea8d5f6348273b","repo":"jackwener/OpenCLI","slug":"label-request-failed-err-message-err-74ea8d","errorCode":null,"errorMessage":"${label} request failed: ${err?.message ?? err}","messagePattern":"(.+?) request failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/rubygems/utils.js","lineNumber":53,"sourceCode":"    if (!s) {\n        throw new ArgumentError('rubygems gem name is required (e.g. \"rails\", \"sidekiq\")');\n    }\n    if (s.length > 100 || !GEM_NAME.test(s)) {\n        throw new ArgumentError(\n            `rubygems gem \"${value}\" is not a valid gem name`,\n            'Use letters / digits / \"._-\", starting with a letter or digit (max 100 chars).',\n        );\n    }\n    return s;\n}\n\nexport async function gemsFetch(url, label) {\n    let resp;\n    try {\n        resp = await fetch(url, { headers: { 'user-agent': UA, accept: 'application/json' } });\n    }\n    catch (err) {\n        throw new CommandExecutionError(\n            `${label} request failed: ${err?.message ?? err}`,\n            'Check that rubygems.org is reachable from this network.',\n        );\n    }\n    if (resp.status === 404) {\n        throw new EmptyResultError(label, `RubyGems returned 404 for ${url}.`);\n    }\n    if (resp.status === 429) {\n        throw new CommandExecutionError(\n            `${label} returned HTTP 429 (rate limited)`,\n            'RubyGems throttles bursts; wait a few seconds and retry.',\n        );\n    }\n    if (!resp.ok) {\n        throw new CommandExecutionError(`${label} returned HTTP ${resp.status}`);\n    }\n    let body;\n    try {","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/rubygems/utils.js#L35-L71","documentation":"gemsFetch in clis/rubygems/utils.js wraps global fetch; when the fetch itself rejects (network unreachable, DNS failure, TLS error, connection refused) it throws CommandExecutionError(`${label} request failed: ${err?.message ?? err}`) with a hint to check that rubygems.org is reachable. The library converts the raw fetch exception so every command surfaces a consistent, labeled message.","triggerScenarios":"Any rubygems command (search, gem info, etc.) when the initial fetch() to rubygems.org throws: offline machine, DNS failure, blocked firewall/proxy, TLS interception failure.","commonSituations":"Corporate firewall blocking rubygems.org; no internet/VPN in CI; DNS misconfiguration; self-signed corporate TLS proxy rejecting the connection; IPv6-only breakage.","solutions":["Verify reachability: `curl -sv https://rubygems.org/api/v1/search.json?query=rails` — compare its error with the one in the message.","Check DNS: `nslookup rubygems.org`; try `--dns-over-https` style fixes or a different resolver if it fails.","Configure proxy env vars (HTTPS_PROXY/NO_PROXY) so fetch can route out, or bypass a broken corporate proxy.","Retry after checking status — transient blips resolve with one retry; wrap the call in retry-with-backoff."],"exampleFix":"// before\nawait search({ query: 'rails' }); // CommandExecutionError: request failed\n\n// after\nasync function withRetry(fn, n = 3) {\n  for (let i = 0; i < n; i++) {\n    try { return await fn(); }\n    catch (e) {\n      if (i === n - 1 || !/request failed/.test(e.message)) throw e;\n      await new Promise(r => setTimeout(r, 2 ** i * 500));\n    }\n  }\n}\nawait withRetry(() => search({ query: 'rails' }));","handlingStrategy":"retry","validationCode":"// Pre-flight reachability probe\nconst probe = await fetch('https://rubygems.org/api/v1/rubygems.json')\n  .then(r => r.ok).catch(() => false);\nif (!probe) throw new Error('rubygems.org unreachable — check network/proxy');","typeGuard":"function isFetchNetworkError(err) {\n  return err instanceof TypeError || /fetch failed|ENOTFOUND|ECONNREFUSED|ECONNRESET|certificate/i.test(String(err?.cause ?? err));\n}","tryCatchPattern":"async function gemsFetchRetry(url, label, tries = 3) {\n  for (let i = 0; ; i++) {\n    try { return await gemsFetch(url, label); }\n    catch (e) {\n      if (i >= tries - 1 || !/request failed/.test(e.message)) throw e;\n      await new Promise(r => setTimeout(r, 2 ** i * 500 + Math.random() * 250));\n    }\n  }\n}","preventionTips":["Set HTTPS_PROXY/NO_PROXY correctly for restricted networks.","Add exponential-backoff retries around all rubygems calls in scripts and CI.","Monitor rubygems.org status before long bulk jobs.","Exclude TLS-intercepting proxies for rubygems.org if certificates fail."],"tags":["network","fetch","dns","proxy","rubygems"],"backgroundTag":"connection-refused","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}