{"record":{"id":"619ef481a4249f5a","repo":"jackwener/OpenCLI","slug":"medium-tag-returned-http-resp-status","errorCode":null,"errorMessage":"medium tag returned HTTP ${resp.status}","messagePattern":"medium tag returned HTTP (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/medium/tag.js","lineNumber":113,"sourceCode":"        try {\n            resp = await fetch(url, {\n                headers: {\n                    'user-agent': 'opencli-medium-adapter (+https://github.com/jackwener/opencli)',\n                    accept: 'application/rss+xml, application/xml',\n                },\n            });\n        }\n        catch (err) {\n            throw new CommandExecutionError(\n                `medium tag request failed: ${err?.message ?? err}`,\n                'Check that medium.com is reachable from this network.',\n            );\n        }\n        if (resp.status === 404) {\n            throw new EmptyResultError('medium tag', `Medium tag \"${tag}\" does not exist.`);\n        }\n        if (!resp.ok) {\n            throw new CommandExecutionError(`medium tag returned HTTP ${resp.status}`);\n        }\n        const xml = await resp.text();\n        const items = [];\n        const re = /<item[^>]*>([\\s\\S]*?)<\\/item>/g;\n        let m;\n        while ((m = re.exec(xml)) !== null) {\n            items.push(m[1]);\n        }\n        if (!items.length) {\n            throw new EmptyResultError('medium tag', `Medium tag \"${tag}\" RSS feed has no items.`);\n        }\n        return items.slice(0, limit).map((block, i) => ({\n            rank: i + 1,\n            title: decodeHtml(extractTag(block, 'title')).trim(),\n            author: decodeHtml(extractTag(block, 'dc:creator')).trim(),\n            description: stripHtml(extractTag(block, 'description')),\n            categories: extractCategories(block).join(', '),\n            published: isoDateFromRfc822(decodeHtml(extractTag(block, 'pubDate')).trim()),","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/medium/tag.js#L95-L131","documentation":"After the request succeeds and is not a 404, any other non-OK HTTP status (403 rate-limit/bot-block, 5xx server errors, redirects mishandled) triggers CommandExecutionError 'medium tag returned HTTP <status>'. It reports the raw status so the caller can diagnose server-side or anti-bot rejections.","triggerScenarios":"Calling `medium tag <tag>` when Medium responds 403 (Cloudflare/bot mitigation), 429 (rate limited after rapid repeated calls), or 500/502/503 (Medium server issues).","commonSituations":"Hammering the feed endpoint in a loop from CI; requests from datacenter IPs flagged by bot protection; Medium incidents producing 5xx responses.","solutions":["Read the status in the message: 403/429 usually means bot mitigation or rate limiting — back off and retry with delays.","Retry 5xx statuses after a short wait; they are typically transient.","Try from a different network/IP (residential) if 403 persists.","Check Medium's status page during apparent outages."],"exampleFix":"// before (tight loop triggers 429)\nfor (const t of tags) await mediumTag(t);\n// after\nfor (const t of tags) {\n  await mediumTag(t);\n  await new Promise(r => setTimeout(r, 2000));\n}","handlingStrategy":"retry","validationCode":"// optional preflight of the endpoint's health\nconst res = await fetch('https://medium.com/feed/tag/programming');\nif (!res.ok && res.status !== 404) throw new Error(`Medium unhealthy: HTTP ${res.status}`);","typeGuard":null,"tryCatchPattern":"try {\n  await run(['medium', 'tag', tag]);\n} catch (e) {\n  const m = /returned HTTP (\\d+)/.exec(e.message);\n  if (m && (m[1].startsWith('5') || m[1] === '429')) {\n    await backoffRetry(() => run(['medium', 'tag', tag]), 3);\n  } else throw e;\n}","preventionTips":["Throttle requests to the feed endpoint; add delays between batch calls.","Retry only transient statuses (429, 5xx) with exponential backoff.","Avoid running from datacenter IPs that trip bot mitigation.","Alert on sustained 403/429s rather than hot-looping retries."],"tags":["http","rate-limit","cli","command-execution-error"],"backgroundTag":"http-error-status","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}