Skip to content

OpenDAL backend incompatible with async runtime? #522

Description

@freix1

I am trying to use rustic within a tauri application and I am running into some issues when trying to use an OpenDALBackend within an async function.

Please note that the code snippets below are just quick reproduction examples and do not represent any reason for why I would want to use async.

The following non-async function call works completely fine:

#[tauri::command]
pub fn check_repository() -> Result<(), String> {
    let mut mapped_options = BTreeMap::new();
    mapped_options.insert("root".to_string(), "C:\\restic_backup".to_string());

    let backend_opts = BackendOptions::default()
        .options(mapped_options)
        .repository("opendal:fs")
        .to_backends()
        .unwrap();

    let repo = rustic_core::Repository::new(&RepositoryOptions::default(), &backend_opts)
        .unwrap()
        .open(&Credentials::password("123"))
        .unwrap()
        .to_indexed()
        .unwrap();

    let opts = CheckOptions::default().trust_cache(true);
    repo.check(opts).unwrap();

    Ok(())
}

As soon as I make it an async function, it will no longer work:

#[tauri::command]
pub async fn check_repository() -> Result<(), String> {
    let mut mapped_options = BTreeMap::new();
    mapped_options.insert("root".to_string(), "C:\\restic_backup".to_string());

    let backend_opts = BackendOptions::default()
        .options(mapped_options)
        .repository("opendal:fs")
        .to_backends()
        .unwrap();

    let repo = rustic_core::Repository::new(&RepositoryOptions::default(), &backend_opts)
        .unwrap()
        .open(&Credentials::password("123"))
        .unwrap()
        .to_indexed()
        .unwrap();

    let opts = CheckOptions::default().trust_cache(true);
    repo.check(opts).unwrap();

    Ok(())
}

When I change the repository to use the LocalBackend it will work with async as well:

#[tauri::command]
pub async fn check_repository() -> Result<(), String> {
    let mut mapped_options = BTreeMap::new();
    mapped_options.insert("root".to_string(), "C:\\restic_backup".to_string());

    let backend_opts = BackendOptions::default()
        .options(mapped_options)
        .repository("C:\\restic_backup")
        .to_backends()
        .unwrap();

    let repo = rustic_core::Repository::new(&RepositoryOptions::default(), &backend_opts)
        .unwrap()
        .open(&Credentials::password("123"))
        .unwrap()
        .to_indexed()
        .unwrap();

    let opts = CheckOptions::default().trust_cache(true);
    repo.check(opts).unwrap();

    Ok(())
}

The following is the log output I get when trying to run the second code snippet, which indicates that OpenDAL tries to start its own runtime, but is likely unable to because it is called within the context of the tauri::async_runtime:

[2026-06-15][15:59:28][DEBUG][opendal_service_fs::backend] backend build started: FsBuilder { config: FsConfig { root: Some("C:\\restic_backup"), atomic_write_dir: None } }
[2026-06-15][15:59:28][DEBUG][opendal_service_fs::backend] backend use root C:\restic_backup

[2026-06-15][15:59:28][DEBUG][opendal::services] service=fs name= path=config: stat started
thread 'tokio-rt-worker' (25260) panicked at C:\Users\USERNAME\.cargo\registry\src\index.crates.io-1949cf8c6b5b557f\opendal-core-0.57.0\src\blocking\operator.rs:156:21:
Cannot start a runtime from within a runtime. This happens because a function (like `block_on`) attempted to block the current thread while the thread is being used to drive asynchronous tasks.
stack backtrace:
[2026-06-15][15:59:28][DEBUG][opendal::services] service=fs name= path=config: stat finished

Is there any workaround for this or should I just resort to not using async when interacting with OpenDAL?
Apologies if there is something obvious I am missing regarding this interaction or if this is an issue that is not directly related to rustic.

Metadata

Metadata

Assignees

No one assigned

    Labels

    S-triageStatus: Waiting for a maintainer to triage this issue/PR

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions