usebruno/bruno · error · VaultError
Status ${statusCode}
Error message
Status ${statusCode} What it means
Thrown by handleVaultResponse when the Vault server returns a status other than 200/204 on a non-/sys/health path AND the response body has no usable errors[] array. It is the fallback branch of the node-vault drop-in: when Vault (or something in front of it) gives an error shape the client does not recognize, the client cannot extract a real reason and reports only the raw HTTP status. The thrown value is a VaultError carrying { statusCode, body } so callers can still inspect both.
Source
Thrown at packages/bruno-requests/src/utils/node-vault.ts:128
// Success responses
if (statusCode === 200 || statusCode === 204) {
return body;
}
// Health endpoint special handling (matches node-vault behavior)
if (path.match(/sys\/health/) !== null) {
return body;
}
// Error responses
let message: string;
if (body && body.errors && body.errors.length > 0) {
message = body.errors[0];
} else {
message = `Status ${statusCode}`;
}
throw new VaultError(message, { statusCode, body });
}
/**
* Creates a Vault client instance
*
* This is a drop-in replacement for node-vault, implementing only the methods
* used by bruno-electron and bruno-cli.
*
* @param config - Configuration options
* @returns VaultClient instance with mutable properties
*
* @example
* ```javascript
* const vault = createVaultClient({ apiVersion: 'v1' });
* vault.endpoint = 'https://vault.example.com';
* vault.token = 'my-token';
* const secret = await vault.read('secret/data/myapp');
* ```View on GitHub (pinned to 9bdd81c7bd)
Solutions
- Catch VaultError and read err.details.statusCode and err.details.body to recover the real cause before falling back to the generic message.
- For 403: re-authenticate the token (vault.token = newToken) and retry once.
- For 404: verify the path and apiVersion (e.g. secret/data/... for kv-v2 vs secret/... for kv-v1).
- For 5xx with an HTML/plain body: inspect whether an intermediate proxy or Vault's listener is misconfigured; check Vault seal status and upstream health.
- Enable the client debug callback (config.debug) to log statusCode/body for unresolved cases.
Example fix
// before
const secret = await vault.read('secret/data/myapp');
// after
try {
const secret = await vault.read('secret/data/myapp');
} catch (e) {
if (e?.constructor?.name === 'VaultError' && e.details?.statusCode === 403) {
vault.token = await refreshToken();
return vault.read('secret/data/myapp');
}
throw e;
} Defensive patterns
Strategy: try-catch
Validate before calling
// Before bulk reads, cheaply verify reachability and auth shape.
async function vaultOk(vault) {
try {
const health = await vault.read('sys/health'); // health endpoint bypasses the generic throw
return !health?.sealed && !health?.standby;
} catch {
return false;
}
}
if (!(await vaultOk(vault))) {
throw new Error('Vault unreachable/sealed before request');
} Type guard
function isVaultError(e) {
return e instanceof Error && e.constructor && e.constructor.name === 'VaultError'
&& Object.prototype.hasOwnProperty.call(e, 'details');
}
// or, if VaultError is exported: return e instanceof VaultError; Try / catch
try {
return await vault.read(path);
} catch (e) {
if (!isVaultError(e)) throw e;
const { statusCode, body } = e.details ?? {};
if (statusCode === 403) { vault.token = await refreshToken(); return await vault.read(path); }
if (statusCode === 404) return null; // treat missing secret as absent
if (statusCode >= 500) throw new Error(`Vault upstream error ${statusCode}: ${safeBody(body)}`);
throw e;
} Prevention
- Always read err.details.statusCode/body rather than trusting the generic 'Status N' message.
- Refresh tokens proactively before expiry instead of relying on 403 recovery.
- Pin apiVersion and path layout (kv-v2 uses secret/data/...) to avoid 404 false-negatives.
- Health-check sys/health at startup to fail fast on sealed/unreachable Vault.
When it happens
Trigger: Any Vault read/write/list/delete returns 3xx/4xx/5xx with a body that is not JSON, is empty, or lacks a top-level errors array. Examples: 403 with a plain {'permission_denied': true} shape; 404 with empty body on a wrong path; 502/504 HTML from a reverse proxy or load balancer sitting in front of Vault; 429 with a rate-limit body not using the errors convention; 473/503 while Vault is sealed or standby.
Common situations: Token expired or revoked (403) but Vault returns a non-standard body; wrong mount path (404); Vault sealed or in standby behind a VIP; a corporate proxy/gateway intercepting the request and returning an HTML error page; self-signed cert rejected by an upstream that then returns a generic 502.
Related errors
- Could not reach the mock server
- Error reading cert/key file
- AES256 decryption failed: ${fallbackErr.message}
- Invalid system http_proxy "${http_proxy}": ${error.message}
- Invalid system https_proxy "${https_proxy}": ${error.message
AI-assisted analysis of usebruno/bruno@9bdd81c7bd (2026-08-13).
Data as JSON: /api/errors/7f3577d47e5334d0.
Report an issue: GitHub.