t8y2/dbx · error
Backup destination is invalid
Error message
Backup destination is invalid
What it means
The backup() helper validates the destination path: it must be non-empty after trimming and contain no NUL bytes. Anything else returns this error before touching the filesystem, since rusqlite would fail opaquely on such paths.
Source
Thrown at crates/dbx-sqlite-worker/src/runtime.rs:200
let row_size = serde_json::to_vec(&values).map(|encoded| encoded.len()).unwrap_or(0);
if !rows.is_empty() && encoded_bytes + row_size > MAX_RESPONSE_JSON_BYTES {
truncated = true;
break;
}
encoded_bytes += row_size;
rows.push(values);
},
Err(error) => return WorkerBody::err(error.to_string()),
}
WorkerBody::query(columns, column_types, rows, 0, truncated)
}
Err(error) => WorkerBody::err(error.to_string()),
}
}
fn backup(conn: &Connection, dest: &str) -> WorkerBody {
if dest.trim().is_empty() || dest.contains('\0') {
return WorkerBody::err("Backup destination is invalid");
}
if let Some(parent) = Path::new(dest).parent() {
if !parent.as_os_str().is_empty() {
if let Err(error) = std::fs::create_dir_all(parent) {
return WorkerBody::err(error.to_string());
}
}
}
match conn.backup(DatabaseName::Main, dest, None) {
Ok(()) => WorkerBody::ok(),
Err(error) => WorkerBody::err(format!("SQLite backup failed: {error}")),
}
}
fn restore(conn: &mut Connection, src: &str) -> WorkerBody {
if src.trim().is_empty() || src.contains('\0') {
return WorkerBody::err("Restore source is invalid");
}View on GitHub (pinned to c0390bff16)
Solutions
- Provide a concrete, non-empty destination path for the backup
- Strip NUL bytes when converting paths from raw bytes/C strings
- Validate the destination on the caller side before sending the Backup op
- Ensure the destination directory exists or is creatable (parent dirs are auto-created on success paths)
Example fix
// before
let dest = opts.dest.unwrap_or_default(); // ""
send(Backup { dest });
// after
let dest = opts.dest.ok_or("backup destination required")?;
assert!(!dest.trim().is_empty() && !dest.contains('\0'));
send(Backup { dest }); Defensive patterns
Strategy: validation
Validate before calling
fn validate_backup_dest(dest: &str) -> Result<&str, &'static str> {
if dest.trim().is_empty() { return Err("backup destination is required"); }
if dest.contains('\0') { return Err("backup destination contains NUL byte"); }
Ok(dest)
} Type guard
fn is_safe_path(p: &str) -> bool { !p.trim().is_empty() && !p.contains('\0') } Try / catch
match worker.send(WorkerOp::Backup { dest: dest.to_string() }).await {
Err(body) if body.error() == Some("Backup destination is invalid") => {
eprintln!("Provide a non-empty destination path without NUL bytes");
}
other => other?,
} Prevention
- Make the backup path a required argument (no defaults to empty string)
- Sanitize paths built from raw bytes to strip NULs
- Validate path client-side before dispatching ops
- Test backup commands with missing-path scenarios
When it happens
Trigger: WorkerOp::Backup with dest = "", whitespace-only, or a string containing '\0'; a config/argument that never supplied the destination; joining paths programmatically that embedded a NUL.
Common situations: Missing CLI arg or unset env var for the backup path; trimming logic that emptied the value; paths built from byte buffers with trailing NULs.
Related errors
- Restore source is invalid
- SQL is empty
- SQLite backup failed: {error}
- Agent runtime thread limits must be positive
- Databend procedure names with special characters are not sup
AI-assisted analysis of t8y2/dbx@c0390bff16 (2026-09-05).
Data as JSON: /api/errors/a4d7bb6809b0fdc4.
Report an issue: GitHub.