{"record":{"id":"430230aa7bf6a474","repo":"jackwener/OpenCLI","slug":"fetch-error-430230","errorCode":"FETCH_ERROR","errorMessage":"Unable to reach paperreview.ai: ${getErrorMessage(error)}","messagePattern":"Unable to reach paperreview\\.ai: (.+?)","errorType":"error_code","errorClass":"CliError","httpStatus":null,"severity":"critical","filePath":"clis/paperreview/utils.js","lineNumber":98,"sourceCode":"        buffer = await fs.readFile(resolvedPath);\n    }\n    catch {\n        throw new CliError('FILE_READ_ERROR', `Unable to read file: ${resolvedPath}`, 'Check file permissions and try again');\n    }\n    return {\n        buffer,\n        fileName,\n        resolvedPath,\n        sizeBytes: buffer.byteLength,\n    };\n}\nexport async function requestJson(pathname, init = {}) {\n    let response;\n    try {\n        response = await fetch(`${PAPERREVIEW_BASE_URL}${pathname}`, init);\n    }\n    catch (error) {\n        throw new CliError('FETCH_ERROR', `Unable to reach paperreview.ai: ${getErrorMessage(error)}`, 'Check your network connection and try again');\n    }\n    const rawText = await response.text();\n    let payload = rawText;\n    if (rawText) {\n        try {\n            payload = JSON.parse(rawText);\n        }\n        catch {\n            payload = rawText;\n        }\n    }\n    return { response, payload };\n}\nexport function ensureSuccess(response, payload, fallback, hint) {\n    if (!response.ok) {\n        const code = response.status === 404 ? 'NOT_FOUND' : 'API_ERROR';\n        throw new CliError(code, toErrorMessage(payload, fallback), hint);\n    }","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/paperreview/utils.js#L80-L116","documentation":"requestJson() performs fetch(`${PAPERREVIEW_BASE_URL}${pathname}`). If the fetch itself rejects — before any HTTP response is received — it throws FETCH_ERROR 'Unable to reach paperreview.ai: <cause>'. This wraps network-level failures such as DNS resolution failure, connection refused/timeout, or TLS errors.","triggerScenarios":"Any requestJson() call (upload URL request, confirm, status, review fetch) where fetch() rejects: no network, DNS failure for paperreview.ai, proxy/firewall blocking HTTPS, TLS interception with untrusted CA, IPv6-only environment lacking IPv4 route, offline machine.","commonSituations":"Corporate proxy without HTTPS_PROXY env set; VPN down; DNS server unreachable; self-signed MITM proxy (Zscaler/Netgear) whose CA is not in the trust store; airport/captive portal not yet authenticated.","solutions":["Check basic connectivity: curl -v https://paperreview.ai — fix network/VPN/DNS if it fails","Set proxy env vars if behind a corporate proxy: export HTTPS_PROXY=http://proxy:port","If TLS interception is used, install the corporate CA into the Node trust store (NODE_EXTRA_CA_CERTS=/path/ca.pem)","Retry after confirming the service is up (status.paperreview.ai or similar) in case of transient outage"],"exampleFix":"// before\nawait requestJson('/api/upload-url', { method: 'POST' }); // fails behind proxy\n// after\n// $ export HTTPS_PROXY=http://corp-proxy:8080\n// $ export NODE_EXTRA_CA_CERTS=/etc/corp/root-ca.pem\nawait requestJson('/api/upload-url', { method: 'POST' });","handlingStrategy":"retry","validationCode":"import net from 'node:net';\nimport tls from 'node:tls';\nasync function canReachPaperreview() {\n    try {\n        await new Promise((resolve, reject) => {\n            const socket = tls.connect({ host: 'paperreview.ai', port: 443, servername: 'paperreview.ai', timeout: 5000 }, resolve);\n            socket.on('error', reject);\n            socket.on('timeout', () => { socket.destroy(); reject(new Error('timeout')); });\n        });\n        return true;\n    } catch { return false; }\n}","typeGuard":null,"tryCatchPattern":"async function requestJsonWithRetry(pathname, init, attempts = 3) {\n    for (let i = 1; i <= attempts; i++) {\n        try { return await requestJson(pathname, init); }\n        catch (e) {\n            if (e?.code === 'FETCH_ERROR' && i < attempts) { await new Promise(r => setTimeout(r, 1000 * 2 ** (i - 1))); continue; }\n            if (e?.code === 'FETCH_ERROR') console.error('Network down:', e.message, '— check VPN/proxy/DNS (HTTPS_PROXY, NODE_EXTRA_CA_CERTS)');\n            throw e;\n        }\n    }\n}","preventionTips":["Set HTTPS_PROXY/HTTP_PROXY when behind a corporate proxy","Install corporate MITM CA via NODE_EXTRA_CA_CERTS","Preflight with `curl -v https://paperreview.ai` in scripts","Implement exponential-backoff retry for transient network failures"],"tags":["network","fetch","dns","connectivity"],"backgroundTag":"unable-to-reach-host","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}