BigPizzaV3/CodexPlusPlus · error · anyhow::Error
Dream Skin image is not a file
Error message
Dream Skin image is not a file
What it means
The source is checked with std::fs::symlink_metadata, which does not follow links: the entry must be a regular file and must not itself be a symlink. Directories, FIFOs, device nodes, and symlinks-to-images are all rejected, so the import always reads a real file.
Source
Thrown at crates/codex-plus-core/src/dream_skin.rs:53
Ok(destination)
}
pub(crate) fn prepare_dream_skin_image_for_directory(
source: &Path,
destination_dir: &Path,
destination_stem: &str,
) -> anyhow::Result<PathBuf> {
if destination_stem.is_empty()
|| !destination_stem
.bytes()
.all(|byte| byte.is_ascii_alphanumeric() || matches!(byte, b'-' | b'_'))
{
bail!("invalid Dream Skin destination name");
}
let metadata = std::fs::symlink_metadata(source)
.with_context(|| format!("failed to read image metadata {}", source.display()))?;
if !metadata.file_type().is_file() || metadata.file_type().is_symlink() {
bail!("Dream Skin image is not a file");
}
if metadata.len() == 0 {
bail!("Dream Skin image is empty");
}
if metadata.len() > DREAM_SKIN_SOURCE_LIMIT {
bail!("Dream Skin source image exceeds 50 MiB");
}
let extension = supported_image_extension(source)?;
std::fs::create_dir_all(destination_dir).with_context(|| {
format!(
"failed to create Dream Skin theme directory {}",
destination_dir.display()
)
})?;
let (prepared_path, prepared_extension) = prepare_image(source, destination_dir, &extension)?;
let prepared_metadata = std::fs::metadata(&prepared_path).with_context(|| {View on GitHub (pinned to f2074595a2)
Solutions
- Resolve the selection with std::fs::canonicalize and pass the resolved regular-file path
- Filter file-picker results to regular files before enabling import
- Prompt for a re-pick when the path no longer resolves to a file
Defensive patterns
Strategy: validation
Validate before calling
fn is_regular_non_symlink(path: &std::path::Path) -> bool {
std::fs::symlink_metadata(path)
.map(|m| m.file_type().is_file() && !m.file_type().is_symlink())
.unwrap_or(false)
} Type guard
fn is_regular_non_symlink(path: &std::path::Path) -> bool {
std::fs::symlink_metadata(path)
.map(|m| m.file_type().is_file() && !m.file_type().is_symlink())
.unwrap_or(false)
} Prevention
- Canonicalize drag-and-drop paths before import
- Reject symlinks explicitly - the library checks with symlink_metadata and will not follow them
- Re-stat immediately before import if the user can modify the file tree in between
When it happens
Trigger: Passing a directory, a Finder alias or an 'ln -s' symlink, a mounted device path, or a stale drag-and-drop path that now resolves to a folder.
Common situations: macOS Finder aliases; users symlinking a Pictures folder into the picker; the target being moved or deleted between selection and import.
Related errors
- Dream Skin image is empty
- invalid Dream Skin destination name
- Dream Skin source image exceeds 50 MiB
- prepared Dream Skin image is empty
- prepared Dream Skin image exceeds 16 MiB
AI-assisted analysis of BigPizzaV3/CodexPlusPlus@f2074595a2 (2026-08-23).
Data as JSON: /api/errors/b782325724f3d102.
Report an issue: GitHub.