{"record":{"id":"7745377e75fbeca7","repo":"koala73/worldmonitor","slug":"search-unavailable","errorCode":null,"errorMessage":"Search unavailable","messagePattern":"Search unavailable","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/crawlable-sources-search.mjs","lineNumber":16,"sourceCode":"// Runs only on the sources directory. Provider details stay on static pages.\nfunction initSourcesSearch() {\n  const search = document.getElementById('source-search');\n  const fields = ['domain', 'kind', 'country', 'coverage'].map((name) => document.getElementById('source-' + name));\n  const results = document.getElementById('source-results');\n  const grid = document.getElementById('source-catalog');\n  const more = document.getElementById('source-more');\n  const note = document.getElementById('source-country-note');\n  const noResults = document.getElementById('source-no-results');\n  let indexPromise;\n  let revision = 0;\n  let offset = 0;\n  const loadIndex = () => {\n    if (!indexPromise) indexPromise = fetch('/sources/search-index.json')\n      .then((response) => {\n        if (!response.ok) throw new Error('Search unavailable');\n        return response.json();\n      }).catch((error) => { indexPromise = null; throw error; });\n    return indexPromise;\n  };\n  const apply = async (nextPage = false) => {\n    const request = ++revision;\n    if (!nextPage) offset = 0;\n    const query = search.value.trim().toLowerCase();\n    const [domain, kind, country, coverage] = fields.map((field) => field.value);\n    grid.replaceChildren();\n    more.hidden = true;\n    noResults.hidden = true;\n    note.hidden = country === 'all' || country === 'intl';\n    note.textContent = note.hidden ? '' : 'This list shows monitored sources based in the selected country or region. Sources based elsewhere also cover it.';\n    if (!query && fields.every((field) => field.value === 'all')) {\n      results.textContent = 'Choose a filter or enter a provider name.';\n      return;\n    }","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/koala73/worldmonitor/blob/7d06c8633d256c18e38133030bc3613976a96ec9/scripts/crawlable-sources-search.mjs#L1-L34","documentation":"loadIndex lazily fetches /sources/search-index.json to build the sources search index. If the response is not ok (404, 500, etc.) it throws 'Search unavailable'. The promise is reset to null in the catch so a later call retries the fetch. The thrown error propagates to callers awaiting the index (e.g. apply()).","triggerScenarios":"GET /sources/search-index.json returns a non-2xx status — the index file was not generated/deployed, the path 404s, or the server errors on that route.","commonSituations":"Deploy pipeline skipped the index build step, the static file is missing from the published assets, an SPA server rewrite returns a 404 for the JSON path, or the site is partially deployed.","solutions":["Verify /sources/search-index.json is reachable in the browser (network tab) and check its HTTP status.","Regenerate/deploy the search index as part of the build (ensure the crawlable-sources-page/index build step ran).","Since loadIndex resets indexPromise on failure, trigger a retry by re-invoking the search action after fixing the file.","If the path is wrong relative to the site base URL, fix the fetch path or server rewrite."],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const res = await fetch('/sources/search-index.json', { method: 'HEAD' });\nif (!res.ok) {\n  console.warn('search index missing; disabling search UI');\n  disableSearch();\n}","typeGuard":null,"tryCatchPattern":"try {\n  const index = await loadIndex();\n} catch (e) {\n  if (e.message === 'Search unavailable') {\n    showSearchFallback('Search is temporarily unavailable.');\n    return; // loadIndex resets its promise, so a later user action will retry\n  }\n  throw e;\n}","preventionTips":["Build and publish sources/search-index.json in the deploy pipeline.","Add a deploy smoke test that HEADs the index URL.","Configure the static server to serve 404 (not HTML rewrites) for missing JSON so failures are explicit.","Since loadIndex retries after failure, surface a retry affordance in the search UI."],"tags":["search","http","missing-asset"],"backgroundTag":"http-error-response","analyzedSha":"7d06c8633d256c18e38133030bc3613976a96ec9","analyzedAt":"2026-09-15T16:44:39.439Z","contentChangedAt":"2026-09-15T16:44:39.439Z","schemaVersion":2},"datasetVersion":"2026-09-15T18:17:12.389Z"}