{"record":{"id":"d1af7f178a25b3e8","repo":"jackwener/OpenCLI","slug":"duckduckgo-suggest-returned-http-resp-status","errorCode":null,"errorMessage":"DuckDuckGo suggest returned HTTP ${resp.status}","messagePattern":"DuckDuckGo suggest returned HTTP (.+?)","errorType":"exception","errorClass":"CommandExecutionError","httpStatus":null,"severity":"error","filePath":"clis/duckduckgo/suggest.js","lineNumber":29,"sourceCode":"  strategy: Strategy.PUBLIC,\n  browser: false,\n  args: [\n    { name: 'keyword', positional: true, required: true, help: 'Search query prefix' },\n    { name: 'limit', type: 'int', default: 8, help: 'Max number of suggestions' },\n  ],\n  columns: ['phrase'],\n  func: async (kwargs) => {\n    const limit = requireBoundedInteger(kwargs.limit, 8, 1, 20, '--limit');\n    const keyword = encodeURIComponent(requireSearchQuery(kwargs.keyword));\n    const url = `https://duckduckgo.com/ac/?q=${keyword}&type=list`;\n    let resp;\n    try {\n      resp = await fetch(url);\n    } catch (err) {\n      throw new CommandExecutionError(`DuckDuckGo suggest request failed: ${err instanceof Error ? err.message : String(err)}`);\n    }\n    if (!resp.ok) {\n      throw new CommandExecutionError(`DuckDuckGo suggest returned HTTP ${resp.status}`);\n    }\n    let data;\n    try {\n      data = await resp.json();\n    } catch (err) {\n      throw new CommandExecutionError(`DuckDuckGo suggest returned malformed JSON: ${err?.message ?? err}`);\n    }\n    const phrases = Array.isArray(data) && data.length > 1 && Array.isArray(data[1]) ? data[1] : [];\n    return phrases\n      .filter((phrase) => typeof phrase === 'string' && phrase.trim())\n      .slice(0, limit)\n      .map(function(p) { return { phrase: p }; });\n  },\n});\n\nexport const __test__ = { command };\n","sourceCodeStart":11,"sourceCodeEnd":46,"githubUrl":"https://github.com/jackwener/OpenCLI/blob/49907e53dc3ade5c223ff0c4c2c2785687cec4e6/clis/duckduckgo/suggest.js#L11-L46","documentation":"After the fetch resolves, the suggest command checks resp.ok. Any non-2xx HTTP status from the DuckDuckGo autocomplete endpoint (429 rate limit, 403 blocked, 5xx server error) produces this CommandExecutionError with the status code embedded. Unlike error 1317, the request reached the server but was rejected.","triggerScenarios":"DuckDuckGo returns 403 (bot/anti-abuse block), 429 (rate limited from rapid repeated calls), 5xx (server-side incident), or a captive portal's 30x/200 HTML handled as non-ok.","commonSituations":"Looping over many keywords too quickly and hitting rate limits; running from datacenter/CI IPs that DuckDuckGo throttles; DuckDuckGo outage; blocked region or VPN IP.","solutions":["Read the embedded HTTP status in the message to identify the cause","Add delays/backoff between suggest requests; back off aggressively on 429","Retry later on 5xx; check DuckDuckGo status if persistent","Use a different network/IP if 403-blocked (avoid datacenter IPs)","Catch CommandExecutionError and degrade gracefully (return empty suggestions)"],"exampleFix":"// before\nfor (const k of keywords) suggestions[k] = await ddgSuggest({ keyword: k });\n// after\nfor (const k of keywords) {\n  await sleep(1000); // avoid 429\n  try { suggestions[k] = await ddgSuggest({ keyword: k }); }\n  catch (e) { suggestions[k] = []; }\n}","handlingStrategy":"retry","validationCode":"// throttle yourself: at most 1 suggest call per second\nlet last = 0;\nasync function throttledSuggest(kw) {\n  const wait = Math.max(0, 1000 - (Date.now() - last));\n  await sleep(wait); last = Date.now();\n  return ddgSuggest({ keyword: kw });\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await ddgSuggest({ keyword });\n} catch (err) {\n  const m = /HTTP (\\d+)/.exec(err?.message ?? '');\n  const status = m ? Number(m[1]) : 0;\n  if (status === 429 || status >= 500) {\n    await sleep(status === 429 ? 10000 : 2000);\n    return ddgSuggest({ keyword });\n  }\n  if (status === 403 || status === 404) return []; // blocked/not offered\n  throw err;\n}","preventionTips":["Rate-limit suggest requests; back off on 429","Avoid datacenter IPs that get 403-blocked","Monitor for DuckDuckGo outages before blaming your code","Cache suggestion results to reduce call volume"],"tags":["http-status","rate-limit","cli"],"backgroundTag":"http-non-2xx-response","analyzedSha":"49907e53dc3ade5c223ff0c4c2c2785687cec4e6","analyzedAt":"2026-08-29T08:14:47.543Z","schemaVersion":2},"datasetVersion":"2026-08-29T12:17:43.993Z"}