windmill-labs/windmill · error

Failed to initialize oracle client: {e}

Error message

Failed to initialize oracle client: {e}

What it means

The Oracle executor must initialize the Oracle Instant Client native library before opening connections (`oracle::InitParams::init` pointing at `ORACLE_LIB_DIR`). If configuring init params fails (typically the lib dir path doesn't contain the client libraries), the executor returns this error instead of attempting a doomed connect.

Source

Thrown at backend/windmill-worker/src/oracledb_executor.rs:420

        .map_err(|x| Error::ExecutionErr(x.to_string()))?
        .args;

    let reserved_variables =
        get_reserved_variables(job, &client.token, conn, parent_runnable_path).await?;

    let (query, args_to_skip) =
        sanitize_and_interpolate_unsafe_sql_args(query, &sig, &job_args, &reserved_variables)?;

    let (_, errors) = get_statement_values(sig.clone(), &job_args, &args_to_skip);

    if !errors.is_empty() {
        return Err(Error::ExecutionErr(errors.join("\n")));
    }

    if !oracle::InitParams::is_initialized() {
        let _ = oracle::InitParams::new()
            .oracle_client_lib_dir(ORACLE_LIB_DIR.as_str())
            .map_err(|e| anyhow!("Failed to initialize oracle client: {e}"))?
            .init();
    }

    let oracle_conn = tokio::task::spawn_blocking(|| {
        oracle::Connection::connect(database.user, database.password, database.database)
            .map_err(|e| Error::ExecutionErr(e.to_string()))
    })
    .await
    .map_err(to_anyhow)??;

    let conn_a = Arc::new(std::sync::Mutex::new(oracle_conn));

    let queries = parse_sql_blocks(&query, false);

    let result_f = async move {
        let mut results = vec![];
        for (i, q) in queries.iter().enumerate() {
            let (vals, _) = get_statement_values(sig.clone(), &job_args, &args_to_skip);

View on GitHub (pinned to e474e8803c)

Solutions

  1. Install Oracle Instant Client (Basic package) on the worker matching the OS/arch.
  2. Point `ORACLE_LIB_DIR` at the directory containing `libclntsh.so` (not the sdk/ or include dir).
  3. Match the Instant Client major version to what the `oracle` crate's bundled OCI expects, and install libaio/ld-linux deps (Debian: `libaio1`).
  4. If already initialized (`is_initialized()` true), the error is skipped — restart the worker after installing the client.
  5. Verify with `ldd libclntsh.so` that all transitive dependencies resolve.

Example fix

// before: ORACLE_LIB_DIR=/opt/oracle/instantclient_21_x/sdk  (headers, no libs)
// after
# ORACLE_LIB_DIR=/opt/oracle/instantclient_21_13  (contains libclntsh.so)
sudo apt-get install -y libaio1
Defensive patterns

Strategy: validation

Validate before calling

# verify the client library dir before starting the worker
test -f "$ORACLE_LIB_DIR/libclntsh.so" && echo ok || echo "ORACLE_LIB_DIR invalid: $ORACLE_LIB_DIR"
ldd "$ORACLE_LIB_DIR/libclntsh.so" | grep 'not found' && echo 'missing transitive deps (libaio?)'

Prevention

When it happens

Trigger: `do_oracledb` runs on a worker where `ORACLE_LIB_DIR` is set but doesn't point at a valid Instant Client directory (missing libclntsh / oci.dll), or the oracle crate rejects the config (wrong architecture/version of the client libraries).

Common situations: Self-hosted worker without Oracle Instant Client installed; client libs of a major version incompatible with the `oracle` Rust crate; ARM vs x86_64 client mismatch; lib dir env var pointing at the SDK (headers) rather than the lib directory; missing LD_LIBRARY_PATH for transitive deps like libaio.

Related errors


AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03). Data as JSON: /api/errors/b93dbede37517d32. Report an issue: GitHub.