{"record":{"id":"7d8ddbe7ab9ab25c","repo":"actualbudget/actual","slug":"failed-to-fetch-css-from-url-response-status","errorCode":null,"errorMessage":"Failed to fetch CSS from ${url}: ${response.status} ${response.statusText}","messagePattern":"Failed to fetch CSS from (.+?): (.+?) (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/desktop-client/src/style/customThemes.ts","lineNumber":77,"sourceCode":"/**\n * Try fetching actual.css from main branch.\n */\nexport function fetchThemeCss(repo: string): Promise<string> {\n  const url = new URL(\n    `https://raw.githubusercontent.com/${repo}/refs/heads/main/actual.css`,\n  );\n  url.searchParams.set('v', Date.now().toString());\n\n  return fetchDirectCss(url.toString());\n}\n\n/**\n * Fetch CSS from a direct URL (not a GitHub repo).\n */\nexport async function fetchDirectCss(url: string): Promise<string> {\n  const response = await fetch(url, { cache: 'no-store' });\n  if (!response.ok) {\n    throw new Error(\n      `Failed to fetch CSS from ${url}: ${response.status} ${response.statusText}`,\n    );\n  }\n  return response.text();\n}\n\n/** Strip surrounding single or double quotes from a string. */\nfunction stripQuotes(s: string): string {\n  const t = s.trim();\n  if (\n    (t.startsWith(\"'\") && t.endsWith(\"'\")) ||\n    (t.startsWith('\"') && t.endsWith('\"'))\n  ) {\n    return t.slice(1, -1).trim();\n  }\n  return t;\n}\n","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/actualbudget/actual/blob/d4334cb6e6123f4d3bcea1ad6166608884c7e658/packages/desktop-client/src/style/customThemes.ts#L59-L95","documentation":"fetchDirectCss fetches theme CSS over HTTP (used by fetchThemeCss to pull actual.css from raw.githubusercontent.com). It throws this error whenever the HTTP response is not ok (status outside 200-299), e.g. 404 Not Found or 403 rate-limited. The message includes the requested URL and the exact status/statusText so you can tell whether the repo, branch, or file path is wrong.","triggerScenarios":"Calling fetchThemeCss('owner/repo') when the repo does not exist, has no actual.css on the main branch, or is private; or calling fetchDirectCss(url) directly with a URL that returns 404/403/5xx. Also triggered when raw.githubusercontent.com returns a non-2xx response (rate limiting, network proxy errors).","commonSituations":"Typo in the owner/repo slug in a custom theme catalog entry; theme repo renamed or its default branch changed from main to master; actual.css file moved or renamed; GitHub rate limiting (HTTP 403) after many fetches; offline or firewalled environment blocking raw.githubusercontent.com.","solutions":["Verify the repo slug is a valid public GitHub repository (open https://github.com/<owner>/<repo> in a browser).","Confirm actual.css exists at the repo root on the main branch (the fetcher hardcodes refs/heads/main/actual.css).","If the branch is not main, restructure the repo so main is the default branch containing actual.css.","Retry later or serve the CSS yourself via fetchDirectCss if GitHub rate-limits you (HTTP 403).","Check network/proxy connectivity to raw.githubusercontent.com."],"exampleFix":"// before\nconst css = await fetchThemeCss('actualbudget/unknow-theme');\n// after\nconst repo = 'actualbudget/actual'; // verify repo exists and contains actual.css on main\nconst css = await fetchThemeCss(repo);","handlingStrategy":"try-catch","validationCode":"const url = `https://raw.githubusercontent.com/${repo}/refs/heads/main/actual.css`;\nif (!/^[\\w.-]+\\/[\\w.-]+$/.test(repo.trim())) throw new Error('repo must be owner/repo');","typeGuard":null,"tryCatchPattern":"try {\n  const css = await fetchThemeCss(repo);\n} catch (err) {\n  if ((err as Error).message.includes('Failed to fetch CSS')) {\n    // surface the URL/status to the user; offer manual CSS entry via fetchDirectCss fallback\n  } else throw err;\n}","preventionTips":["Verify the repo publicly serves actual.css on the main branch before installing.","Handle GitHub 403 rate limits with backoff.","Provide a fallback path to paste CSS manually when the network fetch fails."],"tags":["network","http","fetch","theme-installation"],"backgroundTag":"http-non-2xx-response","analyzedSha":"d4334cb6e6123f4d3bcea1ad6166608884c7e658","analyzedAt":"2026-08-29T01:02:11.213Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}