{"record":{"id":"ba3d57799dad9c01","repo":"pbakaus/impeccable","slug":"impeccable-detect-could-not-read-linked-styleshee","errorCode":null,"errorMessage":"impeccable detect: could not read linked stylesheet {href} (resolved to {css_path}); color and custom-property rules will be incomplete\\n","messagePattern":"impeccable detect: could not read linked stylesheet (.+?) \\(resolved to (.+?)\\); color and custom-property rules will be incomplete\\\\n","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/html/src/cascade/build.rs","lineNumber":124,"sourceCode":"    let file_dir_str = file_dir.to_string_lossy().into_owned();\n    for link in doc.query_selector_all(\"link\") {\n        let rel = link.get_attribute(\"rel\").unwrap_or(\"\");\n        let href = link.get_attribute(\"href\").unwrap_or(\"\");\n        if !STYLESHEET_REL_RE.is_match(rel) || href.is_empty() || REMOTE_HREF_RE.is_match(href) {\n            continue;\n        }\n        let css_path = resolve_linked_css_path(&file_dir_str, href);\n        let read = profile::step(\n            profile,\n            Meta::new(\"preprocess\", \"inline-linked-stylesheet\", file_path).with_detail(href),\n            || std::fs::read(&css_path),\n        );\n        match read {\n            Ok(bytes) => style_texts.push(String::from_utf8_lossy(&bytes).into_owned()),\n            Err(_) => {\n                if warned_missing_stylesheets.insert(css_path.clone()) {\n                    if let Some(warn) = warn {\n                        warn(&format!(\n                            \"impeccable detect: could not read linked stylesheet {href} (resolved to {css_path}); color and custom-property rules will be incomplete\\n\"\n                        ));\n                    }\n                }\n            }\n        }\n    }\n    style_texts.join(\"\\n\")\n}\n\nstatic PSEUDO_RULE_RE: Lazy<Regex> = Lazy::new(|| {\n    Regex::new(&format!(\n        r\"(?i)^(.+?){ws}*::?(?:before|after)$\",\n        ws = js::WS\n    ))\n    .expect(\"PSEUDO_RULE_RE\")\n});\nstatic COLOR_TOKEN_RE: Lazy<Regex> = Lazy::new(|| {","sourceCodeStart":106,"sourceCodeEnd":142,"githubUrl":"https://github.com/pbakaus/impeccable/blob/2bc2879276c1f321a53c4ca99d3371e411329b52/crates/html/src/cascade/build.rs#L106-L142","documentation":"During static detection, collect_static_css_text resolves each <link rel=stylesheet> href against the HTML file's location and reads it from disk to gather color and custom-property rules. When the file cannot be read (missing file, path outside the provided root, unreadable permissions), it emits this warning once per stylesheet (deduplicated via warned_missing_stylesheets) and continues with incomplete CSS, meaning color/contrast and custom-property based checks may be missed for that stylesheet.","triggerScenarios":"Running impeccable detect on an HTML file that references stylesheets via absolute or relative paths that don't resolve under the detection root; the linked CSS file was moved/renamed/deleted; href points to a remote URL or a path outside the sandbox the detector is allowed to read; build output not generated before running detection.","commonSituations":"Pointing the CLI at extracted/single HTML files without the accompanying CSS assets; analyzing dist/ before a build has emitted linked CSS; hrefs rewritten by bundlers (hash-named files that no longer exist); running detection from a different working directory than expected so relative resolution lands elsewhere.","solutions":["Run detection from a directory where the linked stylesheets actually exist relative to the HTML file (include the CSS assets, not just the HTML)","Verify each <link href> resolves on disk from the HTML's own location; fix stale or hash-renamed hrefs by rebuilding first","Serve/analyze built output: run the build before detection so referenced CSS files are emitted","If the stylesheet is intentionally unavailable, treat this as a warning and supply the CSS another way (inline critical CSS or pass the stylesheet explicitly if the API supports it)"],"exampleFix":"<!-- before: href points at a file that does not exist next to the analyzed HTML -->\n<link rel=\"stylesheet\" href=\"/css/main.css\">\n\n<!-- after: href resolves relative to the HTML file on disk -->\n<link rel=\"stylesheet\" href=\"./css/main.css\">","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'node:fs';\nimport { resolve, dirname } from 'node:path';\nimport { parseHTML } from 'linkedom';\nfunction missingStylesheets(htmlPath) {\n  const html = readFileSync(htmlPath, 'utf8');\n  const { document } = parseHTML(html);\n  const base = dirname(htmlPath);\n  return [...document.querySelectorAll('link[rel=\"stylesheet\"]')]\n    .map(l => resolve(base, l.getAttribute('href')))\n    .filter(p => { try { readFileSync(p); return false; } catch { return true; } });\n}","typeGuard":"function stylesheetExists(href, baseDir) {\n  const p = resolve(baseDir, href);\n  try { return readFileSync(p).length > 0; } catch { return false; }\n}","tryCatchPattern":"try {\n  const report = detect_html_source(html, { root: projectDir });\n} catch (err) {\n  if (String(err).includes('could not read linked stylesheet')) {\n    console.warn('Some CSS was unreadable; color checks may be incomplete');\n  } else {\n    throw err;\n  }\n}","preventionTips":["Always pass the HTML file together with its CSS assets in the same relative layout as the built site","Run the project build before static detection so hashed/renamed CSS files exist","Dry-run href resolution (resolve + fs.access) for every <link rel=stylesheet> before invoking detection","When warnings list unreadable stylesheets, fix paths rather than ignoring them — color/custom-property rules drive several checks"],"tags":["css","filesystem","static-analysis"],"backgroundTag":"file-not-found","analyzedSha":"2bc2879276c1f321a53c4ca99d3371e411329b52","analyzedAt":"2026-09-08T04:51:14.109Z","contentChangedAt":"2026-09-08T04:51:14.109Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}