loco-rs/loco · error · std::io::Error
Failed to retrieve file stem
Error message
Failed to retrieve file stem
What it means
An `io::Error` with `InvalidInput` returned by `strip_template_extension` when the given path has no file stem (no final path component usable as a stem). `Path::file_stem()` returns `None` for paths ending in `..`, empty paths, or root-only paths, and this maps that to an error.
Solutions
- Ensure the path passed in has a real file name with a template extension (e.g. `file.t` or `file.html.t`)
- Validate the path with `path.file_stem().is_some()` before calling
- Guard the caller to skip non-file paths like directories or `.`/`..` components
Example fix
// before
generator.strip_template_extension(Path::new(""))?;
// after
let p = Path::new("templates/user.html.t");
assert!(p.file_stem().is_some());
generator.strip_template_extension(p)?; Defensive patterns
Strategy: type-guard
Validate before calling
fn has_stem(p: &Path) -> bool { p.file_stem().is_some() && p.extension().is_some() } Type guard
fn is_strippable(p: &Path) -> bool {
p.file_stem().is_some() && p.to_string_lossy().ends_with(".t")
} Try / catch
match generator.strip_template_extension(&path) {
Ok(stem) => use(stem),
Err(e) => tracing::warn!("skipping non-template path: {e}"),
} Prevention
- Only call strip_template_extension on real file paths discovered by a file walker
- Skip directory or dot entries (., ..) before processing
- Assert paths carry the template extension before stripping
When it happens
Trigger: Calling `strip_template_extension` on a path without a template extension or with no filename component (e.g. `Path::new(""), Path::new("."), Path::new("/"), Path::new("foo/..")`).
Common situations: Programmatic path construction that produced an empty or dotted path before rendering templates; wrong glob/extraction producing paths with no stem.
Related errors
AI-assisted analysis of loco-rs/loco@23639d1e36 (2026-09-12).
Data as JSON: /api/errors/5c84e808aceb0dbd.
Report an issue: GitHub.
Appendix: source
Thrown at loco-new/src/generator/template.rs:114
let mut tera_instance = Tera::default();
self.register_filters(&mut tera_instance);
let mut context = Context::new();
context.insert("settings", &settings);
let rendered_output = tera_instance.render_str(template_content, &context)?;
Ok(rendered_output)
}
/// Removes the ".t" extension from a template file path, if present.
///
/// # Errors
/// if the given path is not contains template extension
pub fn strip_template_extension(&self, path: &Path) -> std::io::Result<PathBuf> {
path.file_stem().map_or_else(
|| {
Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
"Failed to retrieve file stem",
))
},
|stem| {
let mut path_without_extension = path.to_path_buf();
path_without_extension.set_file_name(stem);
if let Some(parent_dir) = path.parent() {
path_without_extension = parent_dir.join(stem.to_string_lossy().to_string());
}
Ok(path_without_extension)
},
)
}
}
#[cfg(test)]
mod tests {View on GitHub (pinned to 23639d1e36)