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
- Install Oracle Instant Client (Basic package) on the worker matching the OS/arch.
- Point `ORACLE_LIB_DIR` at the directory containing `libclntsh.so` (not the sdk/ or include dir).
- Match the Instant Client major version to what the `oracle` crate's bundled OCI expects, and install libaio/ld-linux deps (Debian: `libaio1`).
- If already initialized (`is_initialized()` true), the error is skipped — restart the worker after installing the client.
- 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
- Install Oracle Instant Client (Basic, correct arch) in the worker image
- Point ORACLE_LIB_DIR at the lib dir containing libclntsh.so, not sdk/
- Install libaio and match client major version to the oracle crate
- Restart the worker after installing the client
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
- WORKER_SUFFIX must only contain ASCII letters, digits and un
- WORKER_SUFFIX must be at most {MAX_WORKER_SUFFIX_LABEL_LEN}
- worker name '{name}' is {} characters, more than the {MAX_WO
- EXIT_AFTER_N_JOBS must be a positive integer (or 0 to disabl
- ${what} failed:\n${output}
AI-assisted analysis of windmill-labs/windmill@e474e8803c (2026-09-03).
Data as JSON: /api/errors/b93dbede37517d32.
Report an issue: GitHub.