dani-garcia/vaultwarden · critical
Failed to load
Error message
Failed to load {key}: {e:?} What it means
When a config key is supplied only via KEY_FILE, Vaultwarden reads the file with fs::read_to_string at startup. This panic fires if that file cannot be read (missing, unreadable, or invalid path), aborting configuration loading.
Solutions
- Verify the file exists and is readable by the Vaultwarden process user (ls -l, stat)
- Check container volume/secrets mounts (docker inspect, kubectl get pod -o yaml)
- Fix the X_FILE path in your env configuration; use an absolute path
- Test with: cat $X_FILE inside the container to reproduce the exact OS error shown in the panic
Example fix
// before docker-compose: ADMIN_TOKEN_FILE: ./secrets/admin_token.txt (not copied into image) // after volumes: - ./secrets/admin_token.txt:/run/secrets/admin_token:ro environment: ADMIN_TOKEN_FILE: /run/secrets/admin_token
Defensive patterns
Strategy: validation
Validate before calling
const path = process.env.ADMIN_TOKEN_FILE;
if (path) {
const fs = require('fs');
if (!fs.existsSync(path) || !fs.statSync(path).isFile()) throw new Error(`${path} missing or not a file`);
fs.accessSync(path, fs.constants.R_OK);
} Type guard
function readableFile(p) { try { return typeof p === 'string' && require('fs').statSync(p).isFile() && require('fs').accessSync(p, require('fs').constants.R_OK) === undefined; } catch { return false; } } Prevention
- Mount secret files at stable absolute paths (e.g. /run/secrets/)
- Ensure the container user has read permission on mounted secrets
- Test secret mounts in CI before deploy (cat the file in an init step)
- Avoid relative paths and unexpanded variables in *_FILE values
When it happens
Trigger: X_FILE points to a non-existent file, the process lacks read permission, the path is a directory, or the secret mount failed (empty/failed volume mount in Docker/Kubernetes).
Common situations: Kubernetes secret not mounted before startup; Docker secrets typo in the mount path; SELinux/AppArmor blocking access; file deleted by tmpfs cleanup; path containing trailing whitespace or unexpanded $VARS.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
AI-assisted analysis of dani-garcia/vaultwarden@cc67d644f6 (2026-09-19).
Data as JSON: /api/errors/d7cb87b561e80b10.
Report an issue: GitHub.
Appendix: source
Thrown at src/util.rs:444
} else {
None
}
}
//
// Env methods
//
pub fn get_env_str_value(key: &str) -> Option<String> {
let key_file = format!("{key}_FILE");
let value_from_env = env::var(key);
let value_file = env::var(&key_file);
match (value_from_env, value_file) {
(Ok(_), Ok(_)) => panic!("You should not define both {key} and {key_file}!"),
(Ok(v_env), Err(_)) => Some(v_env),
(Err(_), Ok(v_file)) => match std::fs::read_to_string(v_file) {
Ok(content) => Some(content.trim().to_owned()),
Err(e) => panic!("Failed to load {key}: {e:?}"),
},
_ => None,
}
}
pub fn get_env<V>(key: &str) -> Option<V>
where
V: FromStr,
{
try_parse_string(get_env_str_value(key))
}
pub fn get_env_bool(key: &str) -> Option<bool> {
const TRUE_VALUES: &[&str] = &["true", "t", "yes", "y", "1"];
const FALSE_VALUES: &[&str] = &["false", "f", "no", "n", "0"];
match get_env_str_value(key) {
Some(val) if TRUE_VALUES.contains(&val.to_lowercase().as_ref()) => Some(true),View on GitHub (pinned to cc67d644f6)