{"record":{"id":"804effeb9dcea5a3","repo":"spacedriveapp/spacedrive","slug":"cannot-determine-parent-directory","errorCode":null,"errorMessage":"Cannot determine parent directory","messagePattern":"Cannot determine parent directory","errorType":"exception","errorClass":"FileIOError","httpStatus":null,"severity":"error","filePath":"crates/ffmpeg/src/thumbnailer.rs","lineNumber":29,"sourceCode":"/// `Thumbnailer` struct holds data from a `ThumbnailerBuilder`, exposing methods\n/// to generate thumbnails from video files.\n#[derive(Debug, Clone)]\npub struct Thumbnailer {\n\tbuilder: ThumbnailerBuilder,\n}\n\nimpl Thumbnailer {\n\t/// Processes an video input file and write to file system a thumbnail with webp format\n\tpub(crate) async fn process(\n\t\t&self,\n\t\tvideo_file_path: impl AsRef<Path> + Send,\n\t\toutput_thumbnail_path: impl AsRef<Path> + Send,\n\t) -> Result<(), Error> {\n\t\tlet output_thumbnail_path = output_thumbnail_path.as_ref();\n\t\tlet path = output_thumbnail_path.parent().ok_or_else(|| {\n\t\t\tFileIOError::from_std_io_err(\n\t\t\t\toutput_thumbnail_path,\n\t\t\t\tio::Error::new(\n\t\t\t\t\tio::ErrorKind::InvalidInput,\n\t\t\t\t\t\"Cannot determine parent directory\",\n\t\t\t\t),\n\t\t\t)\n\t\t})?;\n\n\t\tfs::create_dir_all(path)\n\t\t\t.await\n\t\t\t.map_err(|e| FileIOError::from_std_io_err(path, e))?;\n\n\t\tlet webp = self.process_to_webp_bytes(video_file_path).await?;\n\t\tlet mut file = fs::File::create(output_thumbnail_path)\n\t\t\t.await\n\t\t\t.map_err(|e: io::Error| FileIOError::from_std_io_err(output_thumbnail_path, e))?;\n\n\t\tfile.write_all(&webp)\n\t\t\t.await\n\t\t\t.map_err(|e| FileIOError::from_std_io_err(output_thumbnail_path, e))?;","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/spacedriveapp/spacedrive/blob/6dfeccf2113039e35f2ce735f945e70dc3e4ea45/crates/ffmpeg/src/thumbnailer.rs#L11-L47","documentation":"Thumbnailer::process writes a webp thumbnail to output_thumbnail_path and first resolves parent() to create the directory tree. parent() returns None only for paths with no parent component: the empty path or the root '/'. The FileIOError (ErrorKind::InvalidInput) is constructed before any I/O, so this is a caller-argument bug, not an environment failure.","triggerScenarios":"Passing Path::new(\"\") or Path::new(\"/\") as the thumbnail output path; building the path from an empty config field so the join collapses to nothing; a path-construction bug that drops the filename component.","commonSituations":"Thumbnail job enqueued with an unset thumbnail_dir setting; empty string from config for the output path; test harness passing a literal empty path.","solutions":["Log the exact output_thumbnail_path reaching process(): it is empty or '/'","Fix the caller to always build a full file path: dir.join(format!(\"{}.webp\", file_id))","Validate the thumbnail directory setting is non-empty before enqueueing thumbnail jobs"],"exampleFix":"// before: empty config yields Path::new(\"\")\nlet out = PathBuf::from(cfg.thumbnail_dir); // \"\"\nthumb.process(input, out).await?;\n\n// after: validate filename presence before calling\nlet out = cfg.thumbnail_dir.join(format!(\"{}.webp\", id));\nassert!(out.file_name().is_some(), \"thumbnail path needs a filename: {}\", out.display());\nthumb.process(input, out).await?;","handlingStrategy":"validation","validationCode":"// Before calling Thumbnailer::process, require a non-root path with a file name\nfn valid_thumbnail_path(p: &Path) -> bool {\n    p.parent().is_some() && p.file_name().is_some() && !p.as_os_str().is_empty()\n}\nassert!(valid_thumbnail_path(&out));","typeGuard":"fn has_parent_and_filename(p: &Path) -> bool {\n    !p.as_os_str().is_empty() && p != Path::new(\"/\") && p.file_name().is_some()\n}","tryCatchPattern":"// Thumbnailer::process returns Result; match on the FileIOError and log the offending path\nif let Err(e) = thumb.process(input, &out).await {\n    tracing::error!(path = %out.display(), error = %e, \"thumbnail failed; check path construction\");\n}","preventionTips":["Never build output paths from unvalidated config strings","Centralize thumbnail path construction in one helper that asserts file_name() presence","Reject empty thumbnail_dir at config load time"],"tags":["ffmpeg","thumbnail","path-validation"],"backgroundTag":null,"analyzedSha":"6dfeccf2113039e35f2ce735f945e70dc3e4ea45","analyzedAt":"2026-08-16T11:26:17.074Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}