{"record":{"id":"8175b91f06d0b4c9","repo":"loco-rs/loco","slug":"fs-service-should-build-with-success","errorCode":null,"errorMessage":"fs service should build with success","messagePattern":"fs service should build with success","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/storage/drivers/local.rs","lineNumber":27,"sourceCode":"/// as `uploads/avatar.png` lands under the app directory rather than at the\n/// filesystem root. To root the store elsewhere (including an absolute path),\n/// use [`new_with_prefix`].\n///\n/// # Examples\n///```\n/// use loco_rs::storage::drivers::local;\n/// let file_system_driver = local::new();\n/// ```\n///\n/// # Panics\n///\n/// Panics if the filesystem service built failed.\n#[must_use]\npub fn new() -> Box<dyn StoreDriver> {\n    let fs = Fs::default().root(\".\");\n    // opendal 0.58: Operator::new returns a finished Operator (no .finish()).\n    Box::new(OpendalAdapter::new(\n        Operator::new(fs).expect(\"fs service should build with success\"),\n    ))\n}\n\n/// Create new filesystem storage with `prefix` applied to all paths\n///\n/// # Examples\n///```\n/// use loco_rs::storage::drivers::local;\n/// let file_system_driver = local::new_with_prefix(\"users\");\n/// ```\n///\n/// # Errors\n///\n/// Returns an error if the path does not exist\npub fn new_with_prefix(prefix: impl AsRef<std::path::Path>) -> StorageResult<Box<dyn StoreDriver>> {\n    let fs = Fs::default().root(&prefix.as_ref().display().to_string());\n    Ok(Box::new(OpendalAdapter::new(Operator::new(fs)?)))\n}","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/loco-rs/loco/blob/23639d1e360dbc618073642b507d6f8664adbaff/src/storage/drivers/local.rs#L9-L45","documentation":"Loco's local filesystem storage driver builds an OpenDAL `Operator` from a default `Fs` service rooted at \".\". The `Fs` builder's validation (e.g. refusing an invalid or empty root path, or an incompatible option combination) can fail at `Operator::new`; since there is no sensible fallback, the code `.expect()`s and panics with this message.","triggerScenarios":"Calling `loco_rs::storage::drivers::local::new()` when the OpenDAL `Fs` builder rejects its configuration — practically only when the default `.` root becomes invalid, e.g. the current working directory was deleted, or an OpenDAL version change altered builder validation.","commonSituations":"Running the server with its working directory removed (Docker images that delete then re-create cwd); mixing incompatible opendal versions after a dependency bump; constructing the driver in a broken test harness where cwd is unusable.","solutions":["Ensure the process's current working directory exists and is accessible before starting the app","Pin/align the `opendal` version with what loco expects (0.58-style API) in Cargo.lock","Configure a storage root explicitly via config `storage:` settings rather than relying on the `.` default","If constructing manually in tests, chdir to a valid temp dir first (e.g. `std::env::set_current_dir` to a temp path)"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Ensure cwd is usable before building the local storage driver\nlet cwd = std::env::current_dir()?;\nassert!(cwd.exists(), \"current working directory {:?} missing\", cwd);\nlet probe = std::fs::metadata(&cwd)?;","typeGuard":null,"tryCatchPattern":"// Local driver construction is infallible-by-panic; isolate it\nlet driver = std::panic::catch_unwind(loco_rs::storage::drivers::local::new)\n    .map_err(|_| anyhow::anyhow!(\"local storage failed to build; check cwd\"))?;","preventionTips":["Never delete/replace the process working directory while running (careful with Docker layer tricks)","Configure storage roots explicitly in config instead of relying on \".\"","Keep opendal aligned with loco's expected version in Cargo.lock"],"tags":["rust","storage","opendal","filesystem","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"23639d1e360dbc618073642b507d6f8664adbaff","analyzedAt":"2026-09-12T01:47:20.769Z","contentChangedAt":"2026-09-12T01:47:20.769Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}