pbakaus/impeccable · warning

impeccable detect: could not read linked stylesheet {href} (

Error message

impeccable detect: could not read linked stylesheet {href} (resolved to {css_path}); color and custom-property rules will be incomplete\n

What it means

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.

Source

Thrown at crates/html/src/cascade/build.rs:124

    let file_dir_str = file_dir.to_string_lossy().into_owned();
    for link in doc.query_selector_all("link") {
        let rel = link.get_attribute("rel").unwrap_or("");
        let href = link.get_attribute("href").unwrap_or("");
        if !STYLESHEET_REL_RE.is_match(rel) || href.is_empty() || REMOTE_HREF_RE.is_match(href) {
            continue;
        }
        let css_path = resolve_linked_css_path(&file_dir_str, href);
        let read = profile::step(
            profile,
            Meta::new("preprocess", "inline-linked-stylesheet", file_path).with_detail(href),
            || std::fs::read(&css_path),
        );
        match read {
            Ok(bytes) => style_texts.push(String::from_utf8_lossy(&bytes).into_owned()),
            Err(_) => {
                if warned_missing_stylesheets.insert(css_path.clone()) {
                    if let Some(warn) = warn {
                        warn(&format!(
                            "impeccable detect: could not read linked stylesheet {href} (resolved to {css_path}); color and custom-property rules will be incomplete\n"
                        ));
                    }
                }
            }
        }
    }
    style_texts.join("\n")
}

static PSEUDO_RULE_RE: Lazy<Regex> = Lazy::new(|| {
    Regex::new(&format!(
        r"(?i)^(.+?){ws}*::?(?:before|after)$",
        ws = js::WS
    ))
    .expect("PSEUDO_RULE_RE")
});
static COLOR_TOKEN_RE: Lazy<Regex> = Lazy::new(|| {

View on GitHub (pinned to 2bc2879276)

Solutions

  1. Run detection from a directory where the linked stylesheets actually exist relative to the HTML file (include the CSS assets, not just the HTML)
  2. Verify each <link href> resolves on disk from the HTML's own location; fix stale or hash-renamed hrefs by rebuilding first
  3. Serve/analyze built output: run the build before detection so referenced CSS files are emitted
  4. 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)

Example fix

<!-- before: href points at a file that does not exist next to the analyzed HTML -->
<link rel="stylesheet" href="/css/main.css">

<!-- after: href resolves relative to the HTML file on disk -->
<link rel="stylesheet" href="./css/main.css">
Defensive patterns

Strategy: validation

Validate before calling

import { readFileSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { parseHTML } from 'linkedom';
function missingStylesheets(htmlPath) {
  const html = readFileSync(htmlPath, 'utf8');
  const { document } = parseHTML(html);
  const base = dirname(htmlPath);
  return [...document.querySelectorAll('link[rel="stylesheet"]')]
    .map(l => resolve(base, l.getAttribute('href')))
    .filter(p => { try { readFileSync(p); return false; } catch { return true; } });
}

Type guard

function stylesheetExists(href, baseDir) {
  const p = resolve(baseDir, href);
  try { return readFileSync(p).length > 0; } catch { return false; }
}

Try / catch

try {
  const report = detect_html_source(html, { root: projectDir });
} catch (err) {
  if (String(err).includes('could not read linked stylesheet')) {
    console.warn('Some CSS was unreadable; color checks may be incomplete');
  } else {
    throw err;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


AI-assisted analysis of pbakaus/impeccable@2bc2879276 (2026-09-08). Data as JSON: /api/errors/ba3d57799dad9c01. Report an issue: GitHub.