{"record":{"id":"d094c1ef68761443","repo":"aaif-goose/goose","slug":"failed-to-create-directory","errorCode":null,"errorMessage":"Failed to create directory: {}","messagePattern":"Failed to create directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/goose-download-manager/src/lib.rs","lineNumber":259,"sourceCode":"                    model_id: model_id.clone(),\n                    status: DownloadStatus::Downloading,\n                    bytes_downloaded: 0,\n                    total_bytes: total_size_hint,\n                    progress_percent: 0.0,\n                    speed_bps: None,\n                    eta_seconds: None,\n                    error: None,\n                    task_exited: false,\n                },\n            );\n        }\n\n        // Create parent directories for all files\n        for (_, dest) in &files {\n            if let Some(parent) = dest.parent() {\n                tokio::fs::create_dir_all(parent)\n                    .await\n                    .map_err(|e| anyhow::anyhow!(\"Failed to create directory: {}\", e))?;\n            }\n        }\n\n        let downloads = self.downloads.clone();\n        let model_id_clone = model_id.clone();\n        let files_for_cleanup: Vec<PathBuf> = files.iter().map(|(_, d)| d.clone()).collect();\n\n        tokio::spawn(async move {\n            let result = Self::download_files_sequentially(\n                &files,\n                &downloads,\n                &model_id_clone,\n                bearer_token.as_deref(),\n            )\n            .await;\n\n            match result {\n                Ok(_) => {","sourceCodeStart":241,"sourceCodeEnd":277,"githubUrl":"https://github.com/aaif-goose/goose/blob/3810898a7447ec3299be72e223d3570a7aabf0ab/crates/goose-download-manager/src/lib.rs#L241-L277","documentation":"Raised in download_model_sharded_with_bearer_token while preparing the transfer: tokio::fs::create_dir_all on the parent directory of one of the destination paths returned an io::Error, which is appended to the message. No HTTP request is made and the spawned task never runs, so the progress entry inserted just before remains status Downloading with task_exited false until the process restarts.","triggerScenarios":"A destination path whose parent is unwritable (EACCES), sits on a read-only volume, has a regular file where a directory component is needed (ENOTDIR), exceeds name length limits, or the disk is full; also symlink loops or NFS mounts denying creation.","commonSituations":"Download destination rooted outside the goose data dir (e.g. /usr/share or a mounted volume) without write permission; a previous run left a file named like a directory component; sandboxed environments (containers, macOS app containers) restricting writes.","solutions":["Check the exact parent path in the error message: fix ownership/permissions or move the destination under a writable directory such as the goose data dir","Remove any regular file occupying a needed directory component (ls -l on the path in the error)","Free disk space or remount the volume read-write","Verify the path with a manual mkdir -p before rerunning"],"exampleFix":"// before\nmanager.download_model_sharded(id, files, hint, None).await?;\n\n// after: fail with a precise, actionable path before the download starts\nfor (_, dest) in &files {\n    if let Some(parent) = dest.parent() {\n        std::fs::create_dir_all(parent)\n            .map_err(|e| anyhow::anyhow!(\"unwritable download dir {}: {e}\", parent.display()))?;\n    }\n}\nmanager.download_model_sharded(id, files, hint, None).await?;","handlingStrategy":"validation","validationCode":"// prove the destination tree is creatable/writable before starting\nfor (_, dest) in &files {\n    let parent = dest.parent().context(\"destination must have a parent\")?;\n    std::fs::create_dir_all(parent)\n        .with_context(|| format!(\"cannot create download dir {}\", parent.display()))?;\n}","typeGuard":null,"tryCatchPattern":"match err.downcast_ref::<std::io::Error>() {\n    Some(io) if io.kind() == std::io::ErrorKind::PermissionDenied => surface(\"pick a writable folder\"),\n    Some(io) if io.kind() == std::io::ErrorKind::NotADirectory => surface(\"a file occupies the path\"),\n    _ => surface(err),\n}","preventionTips":["Root destinations under the application data dir, not system paths","Run a mkdir -p smoke test in setup/CI on the download root","Treat EACCES/ENOTDIR/EROFS as configuration errors, not transient ones - do not retry"],"tags":["rust","filesystem","permissions","download"],"backgroundTag":null,"analyzedSha":"3810898a7447ec3299be72e223d3570a7aabf0ab","analyzedAt":"2026-08-16T10:14:26.282Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}