{"record":{"id":"00d34c7977cf1182","repo":"jackwener/OpenCLI","slug":"archive-wayback-failed-http-resp-status","errorCode":null,"errorMessage":"archive wayback failed: HTTP ${resp.status}","messagePattern":"archive wayback failed: HTTP (.+?)","errorType":"http","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/archive/wayback.js","lineNumber":58,"sourceCode":"        const timestamp = args.timestamp ? normalizeTimestamp(args.timestamp) : '';\n\n        const apiUrl = new URL('https://archive.org/wayback/available');\n        apiUrl.searchParams.set('url', target);\n        if (timestamp) apiUrl.searchParams.set('timestamp', timestamp);\n\n        let resp;\n        try {\n            resp = await fetch(apiUrl, {\n                headers: {\n                    'Accept': 'application/json',\n                    'User-Agent': 'opencli/1.0 (+https://github.com/jackwener/opencli)',\n                },\n            });\n        } catch (error) {\n            throw new CommandExecutionError(`archive wayback request failed: ${error?.message || error}`);\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`archive wayback failed: HTTP ${resp.status}`);\n        }\n        let data;\n        try {\n            data = await resp.json();\n        } catch (error) {\n            throw new CommandExecutionError(`archive wayback returned malformed JSON: ${error?.message || error}`);\n        }\n\n        const snap = data?.archived_snapshots?.closest;\n        if (!snap || !snap.available) {\n            throw new EmptyResultError('archive wayback', `No Wayback snapshot for \"${target}\".`);\n        }\n        if (typeof snap.url !== 'string' || !snap.url || !/^\\d{14}$/.test(String(snap.timestamp ?? ''))) {\n            throw new CommandExecutionError('archive wayback returned malformed payload: closest snapshot is missing url/timestamp');\n        }\n\n        return [{\n            original_url: String(data.url ?? target),","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/archive/wayback.js#L40-L76","documentation":"Thrown by the `wayback` command in the archive CLI when the Wayback Machine save API responds with a non-2xx HTTP status. The library wraps this in a CommandExecutionError with the status code so the caller knows the archive request itself failed (as opposed to a network error, which is reported separately). It indicates the Wayback service rejected or failed to process the save request.","triggerScenarios":"Calling `opencli archive wayback <url>` when resp.ok is false: HTTP 403/429 rate limiting or bot blocking by web.archive.org, HTTP 5xx while the Wayback service is degraded, or 4xx for URLs the archive refuses.","commonSituations":"Bulk-archiving many URLs in a loop and tripping rate limits; archiving during Wayback outages; URL schemes the Wayback save endpoint rejects.","solutions":["Check resp.status in the message and retry after a delay if 429/503 (Wayback rate limits aggressively)","Test the target URL in a browser at web.archive.org/save/<url> to confirm the service accepts it","Retry later if the status is 5xx — the Wayback service may be temporarily down","If 403 persists, the URL or client may be blocked; try from a different network or use the official Save Page Now API with credentials"],"exampleFix":"// before\nawait exec('opencli archive wayback https://example.com'); // throws on 429\n// after\nfor (let attempt = 0; attempt < 3; attempt++) {\n  try { return await exec('opencli archive wayback ' + url); }\n  catch (e) {\n    if (!/HTTP (429|503)/.test(e.message) || attempt === 2) throw e;\n    await new Promise(r => setTimeout(r, 5000 * (attempt + 1)));\n  }\n}","handlingStrategy":"retry","validationCode":"const url = 'https://example.com';\nif (!/^https?:\\/\\//.test(url)) throw new Error('need an absolute http(s) URL before archiving');","typeGuard":"function isArchivableUrl(u) { return typeof u === 'string' && /^https?:\\/\\/\\S+$/.test(u); }","tryCatchPattern":"try {\n  await runWayback(url);\n} catch (e) {\n  const m = e.message.match(/HTTP (\\d{3})/);\n  if (m && ['429', '502', '503', '504'].includes(m[1])) {\n    await sleep(5000); return runWayback(url); // retry once on rate-limit/server errors\n  }\n  throw e;\n}","preventionTips":["Throttle bulk archiving with delays between requests to avoid 429s","Check web.archive.org status before running large batches","Pre-validate that URLs are absolute and well-formed","Distinguish HTTP-status failures (retryable) from malformed-JSON failures in your catch logic"],"tags":["http","network","archive","wayback"],"backgroundTag":"http-non-2xx-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}