Skip to content

Troubleshooting

Every Upwarden-originated error is prefixed [UPWARDEN] and returns structured JSON. If you don’t see that prefix, the failure is upstream (network, registry, or your package-manager config) — not Upwarden.

{ "error": "Unauthorized" }
  • REQUIRE_PROXY_AUTH is on and the request carried no key or a bad one. Confirm your vk_… key is set in the right env var and sent as Authorization: Bearer … (or Basic, per ecosystem).
  • The key is scoped to a different project/tenant than the host you’re hitting. One key = one project.

A package you expected is blocked (HTTP 403)

Section titled “A package you expected is blocked (HTTP 403)”

The 403 body is a structured JSON envelope. Package managers print the error line; CI / scripts can parse the rest for routing.

{
"error": "[UPWARDEN] Package 'foo@1.2.3' is BLOCKED. Downgrade to known-safe version: 'foo@1.2.2'.",
"advisory": {
"source": "osv",
"id": "GHSA-...-...-...",
"cve": "CVE-2024-12345",
"severity": "HIGH",
"summary": "<one-line explanation of the vulnerability>"
},
"remediation": {
"safe_version": "1.2.2",
"guidance": "<plain-text fix steps>"
}
}

advisory is present when the block is anchored to an OSV / GHSA record; absent for cooldown / oversize / policy blocks. See Verdicts & the scanner → What a 403 carries for the full envelope contract.

Likely causes, most common first:

  • Known vulnerability. advisory.cve is populated, severity will tell you whether to drop everything (CRITICAL / HIGH) or schedule the bump. The remediation.safe_version is the highest known-safe version below the blocked one.
  • Cooldown. VANGUARD_DEFAULT_MIN_AGE_DAYS refuses any version younger than N days (closes the freshly-published-malware window). A brand-new legitimate release trips this. No advisory block. Fix: wait it out, pin an older version, or have your operator lower the cooldown / allow the package.
  • Build-tool fingerprint. The blocked package is a transitive of a known build tool (esbuild, swc, sass-embedded, …). remediation.fingerprint carries the upstream tool name + affected range — bump that tool, not the transitive. See Verdicts → pipeline step 4.
  • Oversized artifact / size-jump anomaly. A prescan hit the decompressed-size cap, or the tarball is more than 5× the median of its three prior versions (a strong compromise signal — see step 4 of the pipeline). Operator adds ecosystem:name to SCANNER_SIZE_ALLOWLIST, or tunes SCANNER_SIZE_JUMP_MULTIPLIER. Don’t allowlist a size-jump without checking the audit row first.
  • Still being scanned (QUARANTINED). A newly-seen version is held up to FAST_PASS_TIMEOUT_MS (default 3s) then quarantined. Retry shortly.
  • True positive. It may actually be unsafe. Check the audit row before overriding — don’t reflexively allowlist.
  • First request for a never-seen version waits on the scanner (fast-pass, up to FAST_PASS_TIMEOUT_MS) before resolving.
  • Scanner backend down/slow: check /healthz and operator logs; SCANNER_ENABLED + EMBEDDING_ENDPOINT.
  • Stale manifest cache: MANIFEST_CACHE_TTL_MS / STALE_MANIFEST_MAX_AGE_MS.
  • Wrong client IP in audit rows / rate-limit buckets: set TRUSTED_PROXY_HOPS to the number of trusted hops in front of Upwarden (GKE Gateway = 1). Default 0 = trust no proxies.
  • Dashboard login fails on staging: COOKIE_SECURE marks the session cookie Secure, which browsers silently drop over plain http://. Set it false for HTTP-only staging.
  • Magic-link “too many requests”: STYTCH_LOGIN_SEND_MAX sends per STYTCH_LOGIN_SEND_WINDOW_SEC (default 10 / 15 min).

Every install and block writes an audit_log row (apiKeyId, package, version, verdict) scoped to your project — the canonical record for why a request was blocked. See Querying the audit log for the query patterns.