slint-ui/slint · error
LICENSE symlink " " is not necessary
Error message
LICENSE symlink "{}" is not necessary What it means
Each symlink in a sub-LICENSES/ directory must correspond to a license actually used by files under that directory, as reported by the parsed SPDX/reuse data (the `licenses` list). This bail fires when a symlink's file stem is not in that list (or is empty), i.e. the link is unnecessary — but only when fix mode is off; with --fix-symlinks the link is silently removed instead.
Solutions
- Remove the unnecessary symlink from the sub-LICENSES/ directory, or re-run with `--fix-symlinks` to have it removed automatically
- If the license IS used, fix the SPDX data: add proper copyright/SPDX headers or REUSE.toml entries so reuse reports that license for the directory
- Check for a typo: symlink stem must exactly equal the license identifier, e.g. `BSD-3-Clause.txt`
Example fix
// before package/LICENSES/MIT.txt -> ../../../LICENSES/MIT.txt (no MIT-licensed files in package) // after rm package/LICENSES/MIT.txt
Defensive patterns
Strategy: validation
Validate before calling
let used: HashSet<String> = licenses_used_in_dir.into_iter().collect();
let linked: Vec<String> = std::fs::read_dir(dir.join("LICENSES"))?.filter_map(|e| e.ok()).filter(|e| is_symlink(&e.path())).filter_map(|e| e.path().file_stem()?.to_str().map(str::to_string)).collect();
let stale: Vec<_> = linked.iter().filter(|l| !used.contains(*l)).collect(); Try / catch
if let Err(e) = run_check() {
if e.to_string().contains("is not necessary") { /* remove the stale symlink or add SPDX headers so the license is detected */ }
else { return Err(e); }
} Prevention
- When removing the last file using a license, also remove its LICENSES/ symlink or run with --fix-symlinks
- Keep SPDX headers/REUSE.toml in sync so the license map matches the symlinks
- After refactors, run the check without --fix first to see stale links
When it happens
Trigger: Running the check without --fix-symlinks while a sub-LICENSES/ dir contains a symlink whose stem matches no license used in that directory (file_stem not in `licenses`), e.g. after removing the only MIT-licensed file but leaving the MIT symlink behind.
Common situations: Stale license symlinks left after deleting/refactoring code; a license symlink added manually for a license not detected by reuse (missing SPDX headers/REUSE.toml entries); a typo in the symlink name.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Invalid extension for LICENSE symlink
- " " is a not a symlink!
- LICENSE symlink " " does not point to a file
- License symlink " " does not point to any existing location
- LICENSE symlink " " points outside the repository
AI-assisted analysis of slint-ui/slint@bb937076de (2026-09-16).
Data as JSON: /api/errors/855b12a397963d65.
Report an issue: GitHub.
Appendix: source
Thrown at xtask/src/reuse_compliance_check.rs:174
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();
let validated_link_target = lic_dir.join(&link_target).canonicalize().unwrap_or_default();
if validated_link_target.as_os_str().is_empty() {
if !fix_it {
anyhow::bail!(View on GitHub (pinned to bb937076de)