BoundaryML/baml · error · LogError
Failed to acquire lock
Error message
Failed to acquire lock
What it means
LogError::LockError is a parameterless variant meaning the logger failed to acquire its internal lock (e.g. a Mutex/PoisonError or try_lock failure) guarding shared logging state. It renders as 'Failed to acquire lock'.
Solutions
- Find and fix any panic occurring while the logger lock is held (poisoned mutex)
- Retry the log call; the lock may be transiently unavailable
- Serialize logging through fewer writer threads or an async channel
- If persistent, reinitialize the logger to replace the poisoned state
Example fix
// before
let _guard = logger.lock().unwrap(); // panics if poisoned
// after
match logger.lock() {
Ok(g) => { /* log */ },
Err(_) => eprintln!("logger lock unavailable"),
} Defensive patterns
Strategy: retry
Validate before calling
// Detect a poisoned logger lock before relying on logging
if logger.lock().is_err() {
eprintln!("logger lock poisoned; reinitializing logger");
} Type guard
fn is_lock_err(e: &LogError) -> bool { matches!(e, LogError::LockError) } Try / catch
for attempt in 0..2 {
match logger.log(record) {
Err(LogError::LockError) if attempt == 0 => continue,
Err(e) => { eprintln!("log failed: {e}"); break; }
Ok(_) => break,
}
} Prevention
- Never panic while holding the logger lock (poisons the mutex)
- Keep log-call bodies minimal to avoid panics inside critical sections
- Use a channel-based logger to decouple logging from lock contention
When it happens
Trigger: Concurrent logging contention where the lock cannot be acquired, or a lock poisoned by a panic in another thread while it was held.
Common situations: High-concurrency multithreaded apps logging simultaneously; a panic inside a logging call poisoning the mutex; using try_lock paths under heavy load.
Related errors
- -32801
- A function call with ID
- call_id is already in use by an active call
- Configuration error
- dynamic-impl table lock poisoned
AI-assisted analysis of BoundaryML/baml@bd85ce9dee (2026-09-12).
Data as JSON: /api/errors/5b6455fcab198036.
Report an issue: GitHub.
Appendix: source
Thrown at engine/baml-lib/baml-log/src/logger.rs:419
static ref CONFIG: RwLock<LogConfig> = RwLock::new(LogConfig::from_env());
static ref LOGGED_LINES: RwLock<HashSet<(Option<String>, Option<String>, Option<u32>)>> = RwLock::new(HashSet::new());
/// Optional log file path — when set, log output goes to this file instead of stdout.
static ref LOG_FILE: Mutex<Option<PathBuf>> = Mutex::new(None);
}
/// Error type for logging operations
#[derive(Debug, Error)]
pub enum LogError {
/// Error writing to output
#[error("IO error: {0}")]
Io(#[from] io::Error),
/// Error serializing to JSON
#[error("JSON serialization error: {0}")]
Json(#[from] serde_json::Error),
/// Error acquiring lock
#[error("Failed to acquire lock")]
LockError,
/// Configuration error
#[error("Configuration error: {0}")]
Config(String),
}
// /// JSON-serializable log entry
// #[derive(Serialize)]
// struct LogEntry<'a> {
// /// Timestamp in ISO 8601 format
// timestamp: String,
// /// Log level as a string
// level: &'a str,
// /// Log message
// message: String,
// /// Optional module path
// #[serde(skip_serializing_if = "Option::is_none")]View on GitHub (pinned to bd85ce9dee)