{"record":{"id":"28380954b137d4d7","repo":"dani-garcia/vaultwarden","slug":"s3-support-is-not-enabled","errorCode":null,"errorMessage":"S3 support is not enabled","messagePattern":"S3 support is not enabled","errorType":"exception","errorClass":"ConfigInvalid","httpStatus":null,"severity":"error","filePath":"src/storage.rs","lineNumber":64,"sourceCode":"    std::path::Path::new(path).file_name()?.to_str().map(str::to_owned)\n}\n\npub(crate) fn is_fs_operator(operator: &opendal::Operator) -> bool {\n    operator.info().scheme() == opendal::services::FS_SCHEME\n}\n\npub(crate) fn operator_for_path(path: &str) -> Result<opendal::Operator, crate::Error> {\n    // Cache of previously built operators by path\n    static OPERATORS_BY_PATH: LazyLock<dashmap::DashMap<String, opendal::Operator>> =\n        LazyLock::new(dashmap::DashMap::new);\n\n    if let Some(operator) = OPERATORS_BY_PATH.get(path) {\n        return Ok(operator.clone());\n    }\n\n    let operator = if path.starts_with(\"s3://\") {\n        #[cfg(not(s3))]\n        return Err(opendal::Error::new(opendal::ErrorKind::ConfigInvalid, \"S3 support is not enabled\").into());\n\n        #[cfg(s3)]\n        s3::operator_for_path(path)?\n    } else {\n        let builder = opendal::services::Fs::default().root(path);\n        opendal::Operator::new(builder)?\n    };\n\n    OPERATORS_BY_PATH.insert(path.to_owned(), operator.clone());\n\n    Ok(operator)\n}\n\n#[cfg(s3)]\nmod s3 {\n    use std::sync::LazyLock;\n\n    use opendal_http_transport_reqwest::ReqwestTransport;","sourceCodeStart":46,"sourceCodeEnd":82,"githubUrl":"https://github.com/dani-garcia/vaultwarden/blob/cc67d644f62605cb46f4d16c4a2eed1a861cc8bb/src/storage.rs#L46-L82","documentation":"operator_for_path returns an OpenDAL config-invalid error when a storage path uses the s3:// scheme but the binary was compiled without the 's3' cargo feature. S3 storage code is cfg-gated out, so the scheme is unsupported.","triggerScenarios":"Setting an attachment/storage path (e.g. ATTACHMENTS_FOLDER) to s3://... and running a Vaultwarden build compiled without --features s3 (or the prebuilt image without S3 support).","commonSituations":"Using the default Docker image that lacks the s3 feature; building from source without cargo build --features s3; switching storage backends without rebuilding the binary.","solutions":["Rebuild with S3 support: cargo build --release --features s3","Use a Docker image/tag built with the s3 feature","Switch attachments back to local filesystem storage (a normal directory path)","Verify enabled features via the build logs or vaultwarden's version/diagnostics endpoint"],"exampleFix":"// before\ncargo build --release\n// after\ncargo build --release --features s3","handlingStrategy":"fallback","validationCode":"if (path.startsWith('s3://') && !features.s3) {\n  throw new Error('s3:// path used but binary lacks the s3 feature; rebuild with --features s3');\n}","typeGuard":"function s3Supported(storagePath) { return !storagePath.startsWith('s3://') || buildFeatures.includes('s3'); }","tryCatchPattern":"try { operator = operatorForPath(path); } catch (e) {\n  if (String(e).includes('S3 support is not enabled')) { logger.error('Rebuild with --features s3 or use local storage'); process.exit(1); }\n  throw e;\n}","preventionTips":["Deploy images built with the feature set your config requires","Gate s3:// config values behind a startup feature check","Pin the Docker image variant that includes S3 support","Run a startup smoke test that resolves the storage operator"],"tags":["s3","storage","feature-flag"],"backgroundTag":"feature-not-enabled","analyzedSha":"cc67d644f62605cb46f4d16c4a2eed1a861cc8bb","analyzedAt":"2026-09-19T08:28:46.370Z","contentChangedAt":"2026-09-19T08:28:46.370Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}