{"record":{"id":"797a9ed8446589dc","repo":"jackwener/OpenCLI","slug":"lobsters-domain-request-failed-err-message","errorCode":null,"errorMessage":"lobsters domain request failed: ${err?.message ?? err}","messagePattern":"lobsters domain request failed: (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/lobsters/domain.js","lineNumber":57,"sourceCode":"    description: 'Lobste.rs stories submitted from a specific domain',\n    domain: 'lobste.rs',\n    strategy: Strategy.PUBLIC,\n    browser: false,\n    args: [\n        { name: 'domain', positional: true, required: true, help: 'Source domain (e.g. github.com, arxiv.org, blog.cloudflare.com)' },\n        { name: 'limit', type: 'int', default: 20, help: 'Number of stories (1-25 — single page)' },\n    ],\n    columns: ['rank', 'id', 'title', 'score', 'author', 'comments', 'created_at', 'tags', 'submission_url', 'comments_url'],\n    func: async (args) => {\n        const domain = requireDomain(args.domain);\n        const limit = requireBoundedInt(args.limit, 20, 25);\n        const url = `https://lobste.rs/domains/${encodeURIComponent(domain)}.json`;\n        let resp;\n        try {\n            resp = await fetch(url, { headers: { 'user-agent': 'opencli-lobsters-adapter (+https://github.com/jackwener/opencli)' } });\n        }\n        catch (err) {\n            throw new CommandExecutionError(\n                `lobsters domain request failed: ${err?.message ?? err}`,\n                'Check that lobste.rs is reachable from this network.',\n            );\n        }\n        if (resp.status === 404) {\n            throw new EmptyResultError('lobsters domain', `No Lobste.rs stories found for domain \"${domain}\".`);\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`lobsters domain returned HTTP ${resp.status}`);\n        }\n        let body;\n        try {\n            body = await resp.json();\n        }\n        catch (err) {\n            throw new CommandExecutionError(`lobsters domain returned malformed JSON: ${err?.message ?? err}`);\n        }\n        const list = Array.isArray(body) ? body : [];","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/lobsters/domain.js#L39-L75","documentation":"Thrown when the fetch() call to https://lobste.rs/domains/<domain>.json itself fails (network-level error: DNS failure, connection refused, TLS error, timeout). The original error's message is wrapped into a CommandExecutionError with the hint 'Check that lobste.rs is reachable from this network.' HTTP error statuses (e.g. 404, 5xx) are handled separately and do NOT produce this error.","triggerScenarios":"fetch() rejects: DNS resolution failure for lobste.rs, no internet/VPN required, firewall or proxy blocking the request, TLS interception, or process offline.","commonSituations":"Running the CLI in a CI container or air-gapped network without egress; corporate proxy not configured (HTTPS_PROXY); DNS blocked by a network filter; laptop offline; lobste.rs temporarily down or blocked by a DNS sinkhole.","solutions":["Verify network connectivity (curl https://lobste.rs/domains/github.com.json) and check whether lobste.rs is reachable from the machine","Check proxy env vars (HTTPS_PROXY/HTTP_PROXY) and that the runtime honors them; configure a proxy if behind a firewall","Inspect the inner message (err?.message) for DNS vs TLS vs timeout specifics and fix accordingly (e.g. VPN on, DNS server changed)","Add retry with backoff for transient outages, or fetch from an alternate network/VPN"],"exampleFix":"// before\nconst stories = await cli.domain('github.com'); // throws offline\n// after\ntry {\n  const stories = await cli.domain('github.com');\n} catch (err) {\n  if (err instanceof CommandExecutionError && /request failed/.test(err.message)) {\n    await retry(() => cli.domain('github.com'), { attempts: 3, backoff: 'exponential' });\n  } else throw err;\n}","handlingStrategy":"retry","validationCode":"// Optional pre-flight reachability probe\nasync function isLobstersReachable(timeoutMs = 5000) {\n  try {\n    const c = new AbortController();\n    const t = setTimeout(() => c.abort(), timeoutMs);\n    await fetch('https://lobste.rs/', { signal: c.signal });\n    clearTimeout(t);\n    return true;\n  } catch { return false;\n  }\n}","typeGuard":"function isNetworkFailure(err) {\n  return err instanceof CommandExecutionError && err.message.includes('lobsters domain request failed');\n}","tryCatchPattern":"try {\n  const stories = await cli.domain(domain);\n} catch (err) {\n  if (isNetworkFailure(err)) {\n    console.error('Cannot reach lobste.rs:', err.message, '- check connectivity/proxy');\n    // retry with backoff for transient failures\n  } else throw err;\n}","preventionTips":["Probe connectivity or serve from cache when lobste.rs is unreachable","Configure HTTPS_PROXY in CI/containers that route through a corporate proxy","Add exponential-backoff retries for transient network errors","Monitor lobste.rs status and surface the inner error message for diagnosis (DNS vs TLS vs timeout)"],"tags":["network","fetch-failure","dns","connectivity","command-execution-error"],"backgroundTag":"network-request-failed","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}