slint-ui/slint · error · std::io::Error

Not an absolute file path

Error message

Not an absolute file path: {path_display}

What it means

The Slint compiler's file loader in the live-preview session can only resolve imported files that map to a `file://` URL. When a compiler import resolves to a relative (non-absolute) path, `Url::from_file_path` fails and the session rejects the load with `InvalidInput`. It exists because the preview loads dependencies over URLs, not raw paths.

Solutions

  1. Make sure imports are resolved to absolute paths before compilation (canonicalize the main file's directory and pass absolute paths in the import path resolver)
  2. Check the import statement in the .slint source — replace ambiguous relative paths with absolute ones or fix the base directory
  3. Pass an explicit include/import path configuration to the compiler so relative imports resolve before the loader sees them

Example fix

// before
import { Widget } from "widgets/widget.slint";
// after (resolve to absolute when configuring the compiler)
let abs = std::fs::canonicalize("widgets/widget.slint")?;
compiler.import_path_resolver(...); // hand back absolute paths
Defensive patterns

Strategy: validation

Validate before calling

if !path.is_absolute() {
    return Err(std::io::Error::new(
        std::io::ErrorKind::InvalidInput,
        format!("Not an absolute file path: {}", path.display()),
    ));
}
let url = Url::from_file_path(path).expect("absolute path converts to file URL");

Type guard

fn is_loadable_path(p: &std::path::Path) -> bool {
    p.is_absolute() && Url::from_file_path(p).is_ok()
}

Prevention

When it happens

Trigger: A `.slint` import inside the compiled file resolves to a relative path (e.g. an import whose path is relative and the loader callback receives it non-absolute), so `Url::from_file_path(path)` returns `Err` in the `set_file_loader` closure of `create_compiler`.

Common situations: Importing a sibling `.slint` file with a relative path that the compiler hands to the file loader unresolved; files loaded from a working directory that differs from the one assumed; embedded/project-relative import strings not normalized to absolute paths before compilation.

Understand the failure class

Background: "Invalid URL" errors: why new URL(), URI.parse, and reqwest::Url reject your string — missing scheme, whitespace, and bad path format — this error's family across 39 libraries.

Related errors


AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16). Data as JSON: /api/errors/98ae103bf2ce51d9. Report an issue: GitHub.

Appendix: source

Thrown at internal/live-preview/preview_sessions.rs:299

    }

    fn create_compiler(self: &Rc<Self>) -> slint_interpreter::Compiler {
        let mut compiler = slint_interpreter::Compiler::new();

        let file_loader_session = Rc::downgrade(self);
        compiler.set_file_loader(move |path: &std::path::Path| {
            let url = Url::from_file_path(path);
            let path_display = path.display().to_string();
            let session = file_loader_session.clone();
            Box::pin(async move {
                let Some(session) = session.upgrade() else {
                    return Some(Err(std::io::Error::new(
                        std::io::ErrorKind::BrokenPipe,
                        "Preview session is no longer available",
                    )));
                };
                let Ok(url) = url else {
                    return Some(Err(std::io::Error::new(
                        std::io::ErrorKind::InvalidInput,
                        format!("Not an absolute file path: {path_display}"),
                    )));
                };
                Some(session.request_file(url).await.map(|file_content| {
                    String::from_utf8_lossy(&file_content.contents).to_string()
                }))
            })
        });

        let mapper_session = Rc::downgrade(self);
        compiler.compiler_configuration(InternalToken).resource_url_mapper =
            Some(Rc::new(move |url: &Url| {
                let session = mapper_session.clone();
                let url = url.clone();
                Box::pin(async move {
                    if url.scheme() != "file" {
                        return None;

View on GitHub (pinned to bb937076de)