{"record":{"id":"c23d33ad8dceffaa","repo":"can1357/oh-my-pi","slug":"every-credential-free-engine-is-excluded-by-settin","errorCode":null,"errorMessage":"Every credential-free engine is excluded by settings.","messagePattern":"Every credential-free engine is excluded by settings\\.","errorType":"exception","errorClass":"SearchProviderError","httpStatus":400,"severity":"error","filePath":"packages/coding-agent/src/web/search/providers/public.ts","lineNumber":126,"sourceCode":" * The fan-out races three exits and returns at the earliest: every engine\n * settled; the soft deadline elapsed with at least one success in hand; the\n * hard deadline elapsed regardless. If the soft deadline fires before any\n * engine has delivered, the aggregate keeps waiting (up to the hard cap) for\n * the first success, so a slow field degrades to fewer engines rather than\n * an empty answer. Stragglers are aborted once the race resolves. Individual\n * engine failures (bot challenges, timeouts) are tolerated; the call fails\n * only when every engine fails.\n */\nexport async function searchPublicWeb(\n\tparams: SearchParams,\n\tdeadlines: PublicWebDeadlines = {},\n): Promise<SearchResponse> {\n\tconst softMs = deadlines.softMs ?? SOFT_DEADLINE_MS;\n\tconst hardMs = deadlines.hardMs ?? HARD_DEADLINE_MS;\n\tconst numResults = clampNumResults(params.numSearchResults ?? params.limit, DEFAULT_NUM_RESULTS, MAX_NUM_RESULTS);\n\tconst engineIds = PUBLIC_ENGINE_IDS.filter(id => !isSearchProviderExcluded(id));\n\tif (engineIds.length === 0) {\n\t\tthrow new SearchProviderError(\"public\", \"Every credential-free engine is excluded by settings.\", 400);\n\t}\n\n\t// Each engine composes its own per-request ceiling on top of the shared\n\t// hard deadline; the straggler controller lets the aggregate cancel\n\t// still-running engines once it decides to return.\n\tconst straggler = new AbortController();\n\tconst signal = AbortSignal.any([withHardTimeout(params.signal, params.timeoutMs), straggler.signal]);\n\n\tconst responses: (SearchResponse | undefined)[] = new Array(engineIds.length);\n\tconst failures: { provider: { id: SearchProviderId; label: string }; error: unknown }[] = [];\n\tconst firstSuccess = Promise.withResolvers<void>();\n\tconst all = Promise.all(\n\t\tengineIds.map(async (id, index) => {\n\t\t\ttry {\n\t\t\t\tconst provider = await getSearchProvider(id);\n\t\t\t\tresponses[index] = await provider.search({ ...params, signal });\n\t\t\t\tfirstSuccess.resolve();\n\t\t\t} catch (error) {","sourceCodeStart":108,"sourceCodeEnd":144,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/web/search/providers/public.ts#L108-L144","documentation":"The Public Web aggregate fans out to a fixed set of credential-free engines (startpage, google, duckduckgo, ecosia, mojeek). If settings exclude every one of them, there is nothing to fan out to, so searchPublicWeb throws a SearchProviderError (status 400) before making any network calls.","triggerScenarios":"Calling the public web search while every PUBLIC_ENGINE_IDS entry is excluded via provider exclusion settings (isSearchProviderExcluded returns true for all five).","commonSituations":"User disabled individual engines after bot-challenge complaints and accidentally excluded all of them; a config template copied exclusion lists verbatim; settings file listing all engines under an exclusion key.","solutions":["Re-enable at least one credential-free engine in settings (remove it from the exclusion list)","Inspect search provider exclusion settings for overly broad entries","Switch the search call to a credentialed provider (Perplexity, Parallel) instead of the public aggregate"],"exampleFix":"// before (settings)\n{ \"search\": { \"excludeProviders\": [\"startpage\",\"google\",\"duckduckgo\",\"ecosia\",\"mojeek\"] } }\n// after\n{ \"search\": { \"excludeProviders\": [\"ecosia\"] } }","handlingStrategy":"validation","validationCode":"import { isSearchProviderExcluded } from \"./web/search/provider\";\nconst engines = [\"startpage\",\"google\",\"duckduckgo\",\"ecosia\",\"mojeek\"];\nif (engines.every(id => isSearchProviderExcluded(id))) {\n  throw new Error('Enable at least one credential-free engine before public web search');\n}","typeGuard":null,"tryCatchPattern":"try {\n  return await searchPublicWeb(params);\n} catch (err) {\n  if (err instanceof SearchProviderError && err.statusCode === 400 && err.message.includes(\"excluded by settings\")) {\n    return credentialedProviderSearch(params);\n  }\n  throw err;\n}","preventionTips":["Never exclude every engine in the credential-free set","Audit copied settings templates for wholesale exclusion lists","Keep one default engine always enabled"],"tags":["configuration","web-search","settings","public-aggregate"],"backgroundTag":"all-providers-excluded","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}