slint-ui/slint · error

Invalid extension for LICENSE symlink

Error message

Invalid extension for LICENSE symlink "{}"

What it means

validate_license_directory derives each LICENSES entry's extension and only allows txt, md, or html so that symlinks match the top-level LICENSES file naming convention. This bail fires when a symlink in a sub-LICENSES/ directory has a missing or disallowed extension. Unlike most checks, this one fires even in fix-it mode because the correct extension cannot be inferred safely.

Solutions

  1. Rename the symlink so its name and extension exactly match the top-level LICENSES file it points to (e.g. Apache-2.0.txt)
  2. Remove the stray symlink and run `cargo xtask reuse-compliance-check --fix-symlinks` to recreate correct ones

Example fix

// before
package/LICENSES/Apache-2.0 -> ../../../LICENSES/Apache-2.0.txt
// after
package/LICENSES/Apache-2.0.txt -> ../../../LICENSES/Apache-2.0.txt
Defensive patterns

Strategy: validation

Validate before calling

let ext = path.extension().and_then(|e| e.to_str()).unwrap_or_default();
if !matches!(ext, "txt" | "md" | "html") { eprintln!("bad extension: {}", path.display()); }

Type guard

fn has_valid_license_ext(path: &std::path::Path) -> bool {
    path.extension().and_then(|e| e.to_str()).map_or(false, |e| matches!(e, "txt" | "md" | "html"))
}

Try / catch

if let Err(e) = run_check() {
    if e.to_string().contains("Invalid extension for LICENSE symlink") { /* rename symlink to match target's name+ext */ }
    else { return Err(e); }
}

Prevention

When it happens

Trigger: scan_symlinks → validate_license_directory encounters a symlink whose name has no extension or one other than .txt/.md/.html (e.g. LICENSES/Apache-2.0, LICENSES/MIT.rst, LICENSES/README).

Common situations: Creating a symlink named `Apache-2.0` without the .txt suffix; using an extension like .rst or .html#frag; an editor/tool creating backup files (e.g. .orig, ~) in LICENSES/.

Understand the failure class

Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.

Related errors


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

Appendix: source

Thrown at xtask/src/reuse_compliance_check.rs:169

            .with_context(|| {
                format!("Failed to read in LICENSES directory \"{}\"", lic_dir.to_string_lossy())
            })?
            .path();

        if !is_symlink(&child) {
            if child.is_file() && fix_it {
                to_remove.push(child.clone());
                continue;
            } else {
                anyhow::bail!("\"{}\" is a not a symlink!", child.to_string_lossy());
            }
        }

        let ext = child.extension().unwrap_or_default();
        let file_stem = child.file_stem().unwrap_or_default().to_string_lossy().to_string();

        if ext.is_empty() || (ext != "txt" && ext != "md" && ext != "html") {
            anyhow::bail!("Invalid extension for LICENSE symlink \"{}\"", child.to_string_lossy());
        }

        if file_stem.is_empty() || !licenses.contains(&file_stem) {
            if !fix_it {
                anyhow::bail!("LICENSE symlink \"{}\" is not necessary", child.to_string_lossy());
            } else {
                to_remove.push(child.clone());
                continue;
            }
        } else {
            linked_licenses.push(file_stem.clone());
        }

        let link_target = std::fs::read_link(&child).with_context(|| {
            format!("Could not extract link target of \"{}\"", child.to_string_lossy())
        })?;
        let link_target_file_stem = link_target.file_stem().unwrap_or_default().to_string_lossy();
        let link_target_extension = link_target.extension().unwrap_or_default();

View on GitHub (pinned to bb937076de)