{"record":{"id":"4c346e802d44f6f3","repo":"lissy93/web-check","slug":"received-non-success-response-code-responsecode","errorCode":null,"errorMessage":"Received non-success response code: ${responseCode}","messagePattern":"Received non-success response code: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"api/status.js","lineNumber":43,"sourceCode":"    startTime = performance.now();\n    const response = await new Promise((resolve, reject) => {\n      const req = https.get(url, { headers: { 'user-agent': UA } }, (res) => {\n        let data = '';\n        responseCode = res.statusCode;\n        res.on('data', (chunk) => {\n          data += chunk;\n        });\n        res.on('end', () => {\n          resolve(res);\n        });\n      });\n\n      req.on('error', reject);\n      req.end();\n    });\n\n    if (responseCode < 200 || responseCode >= 400) {\n      throw new Error(`Received non-success response code: ${responseCode}`);\n    }\n\n    performance.mark('B');\n    performance.measure('A to B', 'A', 'B');\n    let responseTime = performance.now() - startTime;\n    obs.disconnect();\n\n    return { isUp: true, dnsLookupTime, responseTime, responseCode };\n  } catch (error) {\n    obs.disconnect();\n    throw error;\n  }\n};\n\nexport const handler = middleware(statusHandler);\nexport default handler;\n","sourceCodeStart":25,"sourceCodeEnd":60,"githubUrl":"https://github.com/lissy93/web-check/blob/af1a97759fc8bcc43c876c94f2ccb018ce215f90/api/status.js#L25-L60","documentation":"After the raw HTTP request completes, statusHandler checks the response code and throws unless it is in 200-399. This deliberately treats any 4xx/5xx (and anything below 200) as a hard failure, because timing a response the server refused is not meaningful for status reporting of a healthy site.","triggerScenarios":"Target returns 404, 403 (bot-blocked), 500, 503; or non-standard codes below 200. Redirects (3xx) are accepted; 4xx/5xx are not.","commonSituations":"Screenshot-scanner targets behind WAFs that 403 unknown agents, temporarily down origin servers returning 5xx, typo'd paths returning 404, or CDN rate-limit responses (429).","solutions":["Confirm the target responds 2xx/3xx with curl -I and the same User-Agent the checker uses","If the 4xx is bot protection (403/429), adjust headers/UA or rate limiting on the caller side","Treat this as expected signal rather than a bug: report the code to your users instead of crashing"],"exampleFix":"// before\nconst r = await fetch('https://example.com/api/status?url=https://example.com/deleted-page');\n\n// after\nconst target = 'https://example.com/';\nconst probe = await fetch(target, { method: 'HEAD', redirect: 'follow' });\nif (!probe.ok) console.warn(`target returned ${probe.status}, checker will fail`);\nconst r = await fetch(`https://example.com/api/status?url=${encodeURIComponent(target)}`);","handlingStrategy":"try-catch","validationCode":"const probe = await fetch(url, { method: 'HEAD', redirect: 'follow' });\nif (probe.status < 200 || probe.status >= 400) skipStatusCheck(`target already returns ${probe.status}`);","typeGuard":"null","tryCatchPattern":"try { const timing = await statusHandler(url); }\ncatch (e) {\n  if (/non-success response code/.test(e.message)) return { ok: false, reason: e.message };\n  throw e;\n}","preventionTips":["Treat 4xx/5xx as domain signal (report it), not as an exception to crash on","Pre-check target reachability before bulk-checking many URLs","Retain the status code in the error payload so callers can render it"],"tags":["http","status-code","network","uptime"],"backgroundTag":"http-non-success-status","analyzedSha":"af1a97759fc8bcc43c876c94f2ccb018ce215f90","analyzedAt":"2026-08-27T11:44:27.410Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}