Error Code Reference
Support lookup table. Users report code · ref (the ref is the request's error_id); a superuser can fetch the full request context with GET /api/admin/errors/{error_id}.
ERR_REQ_001 — Request could not be processed
- HTTP status: 400
- Severity: warning · Display: toast
- User sees: We couldn't process that request. *Try again. If it keeps happening, contact support and mention the code shown below.*
- Technical context: Base AppError fallback — a slice raised AppError directly instead of a specific subclass. Treat occurrences as a prompt to define a dedicated code.
ERR_REQ_002 — Not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that page or it may have been removed. *Check the link, or head back to your dashboard.*
- Technical context: Generic NotFoundError or an unmatched route (Starlette 404/405 are mapped here too).
ERR_REQ_003 — Conflict
- HTTP status: 409
- Severity: info · Display: toast
- User sees: That change conflicts with the current state of your data. *Refresh to see the latest version, then try again.*
- Technical context: Generic ConflictError fallback. Prefer a specific code (ERR_VAL_006 for stale writes, ERR_ORG_*/ERR_BILL_* for domain conflicts).
ERR_REQ_004 — Too many requests
- HTTP status: 429
- Severity: warning · Display: toast
- User sees: You're doing that a little too fast, so we've paused things briefly. *Wait a moment, then try again.*
- Technical context: RateLimited raised by a rate-limiting dependency (Redis sliding window — provisioned but opt-in). Retry-After is set when known; the frontend disables the triggering control until it elapses.
- ⚠ Ops signal: Burst from a single IP/user on /auth/login = credential stuffing attempt.
ERR_REQ_005 — Payload too large
- HTTP status: 413
- Severity: info · Display: toast
- User sees: That file or request is too large for us to accept. *Try something smaller, or compress the file first.*
- Technical context: Frontend-mapped from a (often bodyless) 413 — usually rejected by the proxy before reaching FastAPI, so no problem+json body exists.
ERR_VAL_001 — Validation failed
- HTTP status: 422
- Severity: info · Display: field
- User sees: Some of the information looks incomplete or incorrect. *Check the highlighted fields and try again.*
- Technical context: Pydantic schema validation failed at the router boundary. The handler flattens pydantic's loc/msg list into the envelope's
fieldsmap so the frontend binds errors to inputs. Raw pydantic messages are passed per-field; the headline copy comes from this catalog. - ⚠ Ops signal: Concentrated on one field right after a deploy = frontend/backend schema drift.
ERR_VAL_002 — Email already registered
- HTTP status: 409
- Severity: info · Display: field
- User sees: An account with this email already exists. *Try signing in instead, or use 'Forgot password' if you don't remember it.*
- Technical context: EmailAlreadyRegistered from AuthService.register (caught before the unique constraint fires). Deliberate enumeration trade-off on a public form for UX; switch to a 'check your email' flow if the threat model changes.
ERR_VAL_003 — Password too weak
- HTTP status: 400
- Severity: info · Display: field
- User sees: That password is too easy to guess. *Use at least 8 characters with a mix of letters and numbers, avoiding common passwords.*
- Technical context: PasswordTooWeak from AuthService.register — the backend blocklist/strength check failed (frontend has a smaller UX-only blocklist for instant feedback).
ERR_VAL_004 — Passwords do not match
- HTTP status: 400
- Severity: info · Display: field
- User sees: The two passwords you entered don't match. *Re-type both passwords so they match exactly.*
- Technical context: PasswordMismatch from AuthService.register. Normally caught client-side first; reaching the backend implies JS-less submission or a frontend bug.
ERR_VAL_005 — Terms not accepted
- HTTP status: 400
- Severity: info · Display: field
- User sees: You'll need to accept the Terms of Service and Privacy Policy to create an account. *Tick the agreement checkbox, then try again.*
- Technical context: TermsNotAccepted from AuthService.register — terms_accepted was false at the API boundary.
ERR_VAL_006 — Edit conflict
- HTTP status: 409
- Severity: info · Display: toast
- User sees: Someone else changed this just now, so we didn't save your edits to avoid overwriting theirs. *Refresh to see the latest version, then re-apply your changes.*
- Technical context: StaleWriteError — optimistic concurrency failure (stale version/updated_at on write). Log both versions' timestamps and the conflicting user_id. Defined in core for slices to adopt.
ERR_VAL_007 — Business email required
- HTTP status: 400
- Severity: info · Display: field
- User sees: Please use your work email to sign up. Free email providers like Gmail or Yahoo aren't accepted. *Enter your company or organization email address.*
- Technical context: FreemailNotAllowed from RegisterUser — the email domain is in the PUBLIC_EMAIL_DOMAINS blocklist. B2B-only signup policy.
ERR_VAL_008 — Permitted use attestation required
- HTTP status: 400
- Severity: info · Display: field
- User sees: You must certify that you won't use this data for FCRA-covered eligibility decisions. *Read and accept the permitted-use attestation, then try again.*
- Technical context: PermittedUseNotAccepted from RegisterUser or CreateApiKey — the permitted_use_accepted flag was false. Compliance gate to keep the product outside FCRA jurisdiction.
ERR_AUTH_001 — Invalid credentials
- HTTP status: 401
- Severity: info · Display: field
- User sees: That email and password combination didn't match our records. *Double-check both fields and try again, or use 'Forgot password' to reset it.*
- Technical context: InvalidCredentials from AuthService.login: user not found OR argon2 verify failed — logged identically for both to prevent user-enumeration timing analysis.
ERR_AUTH_002 — Session expired
- HTTP status: 401
- Severity: info · Display: page
- User sees: Your session has ended, so we signed you out to keep your account safe. *Sign in again to pick up where you left off.*
- Technical context: SessionExpired on the refresh path: cookie missing, token expired (>30d), or hash mismatch after rotation (possible reuse/theft — the token family is revoked). Surfaces when the frontend's transparent tryRefresh() fails; the auth context then signs the user out.
ERR_AUTH_003 — Could not verify sign-in
- HTTP status: 401
- Severity: warning · Display: toast
- User sees: We couldn't verify your sign-in. *Refresh the page. If you're still stuck, sign out and back in.*
- Technical context: Genuinely-anomalous AuthenticationError from auth deps: missing bearer, malformed/bad-signature JWT, unknown or revoked API key, an sk_live_ key sent to a session-only endpoint, or an inactive user. Simple access-token expiry is ERR_AUTH_005, not this. The errctx record (admin error lookup) carries auth_reason — and key_prefix for API-key failures. Often clock skew or a SECRET_KEY mismatch across instances.
- ⚠ Ops signal: Spike right after a deploy = SECRET_KEY mismatch between instances — roll back.
ERR_AUTH_004 — Link invalid or expired
- HTTP status: 400
- Severity: info · Display: page
- User sees: This link is no longer valid — it may have expired or already been used. *Request a fresh link and use it soon after it arrives.*
- Technical context: InvalidActionToken: a purpose-scoped action JWT (email verification or password reset) failed decode, expired, had a purpose mismatch, or the password-reset fingerprint no longer matches (link already used, or the password changed after it was issued). TTLs: EMAIL_VERIFICATION_TTL_HOURS / PASSWORD_RESET_TTL_MINUTES.
ERR_AUTH_005 — Access token expired
- HTTP status: 401
- Severity: info · Display: toast
- User sees: Your sign-in needed a quick refresh. *Retry the request — the app refreshes your session automatically.*
- Technical context: AccessTokenExpired from auth deps: the JWT's exp claim is in the past (ACCESS_TOKEN_TTL_MINUTES, default 15). This is the NORMAL token lifecycle — the frontend transparently refreshes and retries on this 401, so users never see it. Every idle tab produces a burst of these on revisit. High volume is expected; it is severity info precisely so it never drowns the warning-level ERR_AUTH_003 anomalies in the error feed.
ERR_PERM_001 — Permission denied
- HTTP status: 403
- Severity: info · Display: toast
- User sees: You don't have permission to do that in this organization. *Ask an organization admin to upgrade your role, or switch to an organization where you have access.*
- Technical context: InsufficientRole (or base PermissionDeniedError): require_role() passed the membership check but the role rank was insufficient. Log includes org_id, user_id, required vs. actual role.
ERR_PERM_002 — Not found
- HTTP status: 404
- Severity: warning · Display: toast
- User sees: We couldn't find that page or it may have been removed. *Check the link, or head back to your dashboard.*
- Technical context: OrganizationNotFound — deliberate 404-masking per multi-tenancy rule #2: the user is NOT a member of the requested org, and org existence must never leak. The internal log records the real reason; the user copy is identical to a plain 404.
- ⚠ Ops signal: Burst from one user across many org_ids = tenant-enumeration probing — security signal.
ERR_PERM_003 — Invitation invalid
- HTTP status: 404
- Severity: info · Display: page
- User sees: This invitation is no longer valid. *Ask the person who invited you to send a new invitation.*
- Technical context: InvitationInvalid: token expired (>7d), already accepted, or revoked. Log which of the three — a high expired rate suggests the TTL is too short.
ERR_PERM_004 — Administrator access required
- HTTP status: 403
- Severity: warning · Display: page
- User sees: This area is for platform administrators. *Head back to your dashboard. If you believe you should have access, contact an existing administrator.*
- Technical context: NotSuperuser from get_current_superuser — a signed-in non-superuser hit an /admin route. is_superuser is only granted manually in the database.
- ⚠ Ops signal: Repeated hits from one user = someone probing the admin surface.
ERR_ORG_001 — Last owner
- HTTP status: 409
- Severity: info · Display: toast
- User sees: An organization needs at least one owner, and this is the only one. *Make someone else an owner first, then try again.*
- Technical context: LastOwnerError — attempted to demote/remove the sole owner. Raised by OrganizationService role-change/removal paths.
ERR_ORG_002 — Already a member
- HTTP status: 409
- Severity: info · Display: toast
- User sees: That person is already a member of this organization. *Nothing to do — they already have access. Check the Members page.*
- Technical context: AlreadyMember — invitation or acceptance for a user who already holds a membership in the org.
ERR_ORG_003 — Member not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that member in this organization. *Refresh the Members page — they may have already been removed.*
- Technical context: MemberNotFound — membership id valid-shaped but no row in this org (already removed, or cross-org id). Repos filter by organization_id, so cross-tenant ids land here by design.
ERR_ORG_004 — Organization suspended
- HTTP status: 403
- Severity: warning · Display: page
- User sees: This organization has been suspended. *Contact support to resolve the suspension.*
- Technical context: OrgSuspended — organizations.suspended_at is set; require_role blocks every /orgs/{org_id}/* route for all members. Set/cleared by platform admins via /admin/organizations/{id}/(un)suspend.
ERR_ORG_005 — Domain not claimable
- HTTP status: 400
- Severity: info · Display: toast
- User sees: That domain can't be claimed for this organization. *Use your company's own domain — it must match your email address, and shared providers like gmail.com aren't allowed.*
- Technical context: DomainNotClaimable — normalize_claimable_domain rejected the claim: malformed domain, public mailbox provider, or the acting owner's email is not on the domain.
ERR_ORG_006 — Domain already claimed
- HTTP status: 409
- Severity: info · Display: toast
- User sees: Another organization has already claimed that domain. *If this is your company's domain, contact support to resolve the conflict.*
- Technical context: DomainAlreadyClaimed — organizations.email_domain is unique; a different org row already holds this domain.
ERR_ORG_007 — Company workspace already exists
- HTTP status: 409
- Severity: info · Display: field
- User sees: Your company already has a workspace on CoverFi. *Verify your email to join automatically, or ask your company's workspace owner for an invitation.*
- Technical context: DomainOrgExists — CreateOrganization blocked because an org already claims this user's email domain. The user should auto-join via email verification instead.
ERR_ADM_001 — User not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: No user matches that id. *Refresh the user list — the account may have been removed.*
- Technical context: AdminUserNotFound — admin lookup by user id missed. Staff-facing copy; plainer than tenant-facing equivalents.
ERR_ADM_002 — Organization not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: No organization matches that id. *Refresh the organization list — it may have been deleted.*
- Technical context: AdminOrgNotFound — admin lookup by org id missed. Unlike ERR_PERM_002, this is NOT masked: the caller is already a superuser.
ERR_ADM_003 — Cannot deactivate yourself
- HTTP status: 409
- Severity: info · Display: toast
- User sees: You can't deactivate your own account from here. *Ask another administrator to do it, so the platform is never left without an active admin.*
- Technical context: CannotDeactivateSelf — self-deactivation guard on the admin users endpoint.
ERR_ADM_004 — Error record not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: No error record matches that reference. *Check the reference for typos — records also expire after 7 days.*
- Technical context: AdminErrorRecordNotFound — /admin/errors/{error_id} lookup missed in Redis (expired errctx TTL or a mistyped reference).
ERR_ADM_005 — Cannot impersonate a superuser
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: Superuser accounts can't be impersonated. *Impersonation is for regular accounts only — coordinate with the other admin directly.*
- Technical context: CannotImpersonateSuperuser — impersonation guard. Also covers self-impersonation (the acting user is a superuser by definition).
ERR_ADM_006 — Cannot impersonate a deactivated user
- HTTP status: 409
- Severity: info · Display: toast
- User sees: That account is deactivated, so it can't be impersonated. *Reactivate the account first if you need to see it from the inside.*
- Technical context: CannotImpersonateInactive — impersonation guard on users with is_active = false.
ERR_ADM_007 — Invitation not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: No pending invitation matches that id. *Refresh the invitations list — it may already be accepted or revoked.*
- Technical context: AdminInvitationNotFound — cross-tenant invitation lookup missed, or the invitation was already accepted.
ERR_ADM_008 — Invalid merge
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: Cannot merge these organizations. *The target and source organizations must be different, existing organizations.*
- Technical context: MergeInvalid — admin org-merge guard: target not found, source not found, or source == target.
ERR_ADM_009 — Exclusion already exists
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: That organization or domain is already excluded. *Check the current exclusion lists — the entry is already there.*
- Technical context: ExclusionExists — unique (kind, value) guard on metric_exclusions.
ERR_ADM_010 — Invalid exclusion
- HTTP status: 400
- Severity: warning · Display: toast
- User sees: That exclusion isn't valid. *Pick an existing organization, or enter a bare lowercase domain like example.com.*
- Technical context: ExclusionInvalid — unknown organization id or malformed email domain (contains @, spaces, or no dot).
ERR_ADM_011 — Exclusion not found
- HTTP status: 404
- Severity: warning · Display: toast
- User sees: That exclusion no longer exists. *Refresh the settings page — it may have been removed already.*
- Technical context: ExclusionNotFound — DELETE /admin/settings/exclusions/{id} with an unknown id.
ERR_ADM_012 — Dataset source not found
- HTTP status: 404
- Severity: warning · Display: toast
- User sees: That dataset source does not exist. *Refresh the dataset page and choose an available source.*
- Technical context: AdminSourceNotFound — GET /admin/dataset-sources/{source_key} with an unknown catalog key.
ERR_CRD_001 — Not enough credits
- HTTP status: 409
- Severity: info · Display: toast
- User sees: Your organization doesn't have enough credits for this. *Buy a credit pack, then try again.*
- Technical context: InsufficientCredits — the reservation would take the org balance below zero. Include requested vs. available in the log.
- ⚠ Ops signal: A wave across many orgs after a deploy = an action's credit cost was misconfigured.
ERR_CRD_002 — Action already settled
- HTTP status: 409
- Severity: info · Display: toast
- User sees: That action was already completed or cancelled. *Refresh to see the current state — no credits were double-charged.*
- Technical context: ReservationNotActive — finalize/cancel attempted on a non-active credit reservation. This is the double-settlement guard working as intended.
ERR_CRD_003 — Reservation not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that pending action. *Refresh and try again from the start.*
- Technical context: ReservationNotFound — reservation id missing for this org (repos filter by organization_id, so cross-tenant ids land here by design).
ERR_CRD_004 — Unknown action
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: That action isn't available. *Refresh the page — you may be on an older version of the app.*
- Technical context: UnknownAction — credit-cost lookup for an action key that isn't in the pricing table. Usually a stale frontend bundle or a missing pricing entry for a newly shipped action.
ERR_CRD_005 — Unknown credit pack
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: That credit pack isn't available. *Refresh the page and pick one of the listed packs.*
- Technical context: UnknownCreditPack — a CreditPack value missing from the CREDIT_PACKS catalog. Stale frontend bundle, or webhook metadata referencing a pack that was removed from the catalog.
ERR_CRD_006 — Member credit limit reached
- HTTP status: 409
- Severity: info · Display: toast
- User sees: You've reached your monthly credit limit for this organization. *Ask an organization admin to raise your limit, or try again next month.*
- Technical context: MemberCreditLimitExceeded — the acting user's captured + pending reservations this UTC calendar month plus the requested cost exceed member_credit_limits.monthly_limit. API-key charges are exempt (they carry no user_id). The error message includes used vs. requested amounts.
ERR_CRD_007 — Not an organization member
- HTTP status: 404
- Severity: info · Display: toast
- User sees: That person isn't a member of this organization. *Check the member list and try again.*
- Technical context: LimitTargetNotMember — a member-limit set referenced a user_id with no membership in the org (removed member or wrong id).
ERR_GEN_001 — Generation not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that generation. *Head back to your generations list — it may have been removed.*
- Technical context: GenerationNotFound — generation id missing for this org.
ERR_GEN_002 — Generation not available
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: Content generation isn't set up on this server yet. *If you run this deployment, configure the provider API keys (see README). Otherwise, contact your administrator.*
- Technical context: ProviderNotConfigured — the generation provider's API key is empty. Expected in fresh dev environments; in production it's env misconfiguration.
ERR_GEN_003 — Generation failed
- HTTP status: 409
- Severity: error · Display: toast
- User sees: We couldn't finish generating that, and your credits for it have been returned. *Try again. If it keeps failing, tweak your input or contact support with the code below.*
- Technical context: GenerationFailed — the provider call errored; the credit reservation is released (refund), which is what makes the 'credits returned' promise honest. Log the provider error verbatim.
- ⚠ Ops signal: Sustained rate = provider outage or a prompt/template regression — check provider status first.
ERR_GEN_004 — Still generating
- HTTP status: 409
- Severity: info · Display: toast
- User sees: This is still being generated. *Give it a few seconds — the result will appear when it's ready.*
- Technical context: ResultNotReady — result fetched before the generation finished. Normal during polling; only worth attention if a generation never leaves this state.
ERR_GEN_005 — Can't cancel this
- HTTP status: 409
- Severity: info · Display: toast
- User sees: This can only be canceled while it's still generating. *It already finished — refresh to see the result.*
- Technical context: NotCancelable — cancel requested on a non-pending generation. Usually a race between the user clicking cancel and the job finishing; harmless.
ERR_GEN_006 — Can't delete this yet
- HTTP status: 409
- Severity: info · Display: toast
- User sees: Wait until this finishes before deleting it. *Cancel it first, then delete it.*
- Technical context: NotDeletable — delete requested on a still-pending generation. Deleting mid-flight would orphan the credit hold and the in-progress provider job; cancel handles those.
ERR_REC_001 — Record not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that record. *Head back to the browse list — it may have been removed from the dataset.*
- Technical context: RecordNotFound — consumer record id missing, or a malformed (non-UUID) id was requested.
ERR_REC_002 — Insufficient search criteria
- HTTP status: 400
- Severity: info · Display: toast
- User sees: Please narrow your search — we need a bit more to go on. *Add a name plus state, ZIP, or date of birth; an email address; or a phone number.*
- Technical context: InsufficientSearchCriteria — the search did not meet the minimum-input policy (name+state, name+zip, name+dob, email, or phone). Prevents open directory dumps.
ERR_REC_003 — Insufficient address criteria
- HTTP status: 400
- Severity: info · Display: toast
- User sees: Please enter a full street address to look up who has lived there. *Provide a house number and street name, plus either a ZIP or city and state.*
- Technical context: InsufficientAddressCriteria — people-at-address lookup did not meet the minimum-input policy (street + ZIP, or street + city + state). Prevents neighborhood-wide dumps.
ERR_REC_004 — Insufficient identity criteria
- HTTP status: 400
- Severity: info · Display: toast
- User sees: We need a bit more to run an identity check. *Provide a full name, date of birth, and an email or phone number.*
- Technical context: InsufficientIdentityCriteria — identity check missing name, DOB, or contact (email/phone). Mirrors the public free-check form requirements.
ERR_REC_005 — Free search needs a name and state
- HTTP status: 400
- Severity: info · Display: toast
- User sees: Free preview searches need a person's name and state. *Add both a name and a two-letter state, or purchase credits to search by any combination of criteria.*
- Technical context: InsufficientFreeSearchCriteria — an org with no credits ran a search without name + state. Zero-credit orgs only get the blinded preview of a specific-person lookup; flexible criteria (email, phone, name+zip, name+dob) require credits.
ERR_REC_006 — Records search is busy
- HTTP status: 503
- Severity: warning · Display: toast · Auto-retry: 2× after 3000ms
- User sees: Our records search is handling a burst of requests right now. *Wait a few seconds and try again — no credits were used.*
- Technical context: RecordBackendBusy — two sources: (1) the DuckDB admission gate (duckdb_max_concurrent_queries) stayed full past duckdb_queue_wait_seconds, so the query was shed instead of piling onto the shared connection (raised before any credit spend); (2) a Parquet dataset dir was unreadable — mid-dataset-swap, mid-refresh, or absent (by_email/by_phone for contact search, by_address for people-at-address, properties/property_links for property lookups) — so the query 503s instead of silently reporting no results (credit hold released). Sustained occurrences mean the box is undersized, a client is hammering search, or a dataset swap left a dir broken.
- ⚠ Ops signal: A steady stream of these = DuckDB saturation or a broken dataset dir after a swap — check for a scraping org (abuse_alerts), cold-cache partition reads, CPU/memory pressure on the serving box, and that by_email/by_phone/by_address/properties exist and read cleanly.
ERR_REC_007 — Invalid date of birth filter
- HTTP status: 400
- Severity: info · Display: toast
- User sees: That date of birth doesn't look right. *Use YYYY-MM-DD for a full date or YYYY-MM for year and month — e.g. 1985-01-15.*
- Technical context: InvalidDobFilter — the dob search param failed normalization (not exactly 6 or 8 digits after stripping separators, month outside 01-12, day invalid for the month, or year outside 1900..current). Previously the filter was silently dropped and the search still charged a credit; now the request 400s inside the credit hold, which is released — no credit is spent.
ERR_REC_008 — Invalid phone filter
- HTTP status: 400
- Severity: info · Display: toast
- User sees: That phone number doesn't look right. *Enter a 10-digit US phone number, e.g. (555) 123-4567.*
- Technical context: InvalidPhoneFilter — the phone search param is not a 10-digit NANP number (or 11 digits with a leading 1) after stripping formatting. Previously a malformed phone fell back to a raw-string match that returned nothing while still charging; now the request 400s inside the credit hold, which is released — no credit is spent.
ERR_ABU_001 — Records temporarily limited
- HTTP status: 403
- Severity: warning · Display: banner
- User sees: Records access is temporarily limited due to unusual activity. *Wait and try again later, or contact support if you believe this is a mistake.*
- Technical context: RecordsSoftBlocked — organizations.records_soft_blocked_until is in the future. Auto-expires (default 24h). Raised by AssertRecordsAccess before credits are spent. Soft blocks escalate to hard on continued abuse signals.
- ⚠ Ops signal: Soft block applied — review abuse_alerts for the org; sequential pagination / high unique volume / diverse ZIP-email lookups are typical triggers.
ERR_ABU_002 — Records access locked
- HTTP status: 403
- Severity: warning · Display: page
- User sees: Records access for this organization is locked pending review. *Contact support — a human review is required before access can be reinstated.*
- Technical context: RecordsHardBlocked — organizations.records_hard_blocked_at is set. Only cleared by admin reinstate (human review). Soft→hard escalation or hard-threshold detector hits set this.
- ⚠ Ops signal: Hard block — open the admin Abuse queue, review evidence, reinstate only after human review.
ERR_ABU_003 — Abuse alert not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that abuse alert. *Refresh the Abuse queue — it may already have been resolved.*
- Technical context: AbuseAlertNotFound — admin referenced a missing alert id, or reinstate targeted a missing org/alert pair.
ERR_FDBK_001 — Feedback not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that feedback item. *Refresh the Feedback queue — it may already have been closed or redacted.*
- Technical context: FeedbackNotFound — admin lookup by feedback id missed, or the row was purged by the retention sweep.
ERR_FDBK_002 — Screenshot too large
- HTTP status: 400
- Severity: warning · Display: field
- User sees: That screenshot is too large to attach. *Send the feedback without the screenshot — your message still reaches us.*
- Technical context: ScreenshotTooLarge — decoded screenshot exceeded MAX_SCREENSHOT_BYTES. The client downscales to a JPEG before sending, so this usually means a very tall page or a tampered payload.
ERR_PRIV_001 — Privacy request not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that privacy request. *Refresh the queue — it may have been closed or the link is stale.*
- Technical context: PrivacyRequestNotFound — admin lookup by privacy request id missed.
ERR_PRIV_002 — Privacy request cannot be updated
- HTTP status: 409
- Severity: info · Display: toast
- User sees: That privacy request is not in a state that allows this action. *Check the current status, then use the next allowed step (verify → fulfill/forward → close).*
- Technical context: PrivacyRequestInvalidTransition — status machine guard on verify/fulfill/forward/close/reject.
ERR_PRIV_003 — Privacy request incomplete
- HTTP status: 400
- Severity: info · Display: field
- User sees: We need a bit more information to process this privacy request. *Provide a contact email plus an email, phone, or consumer key for the subject.*
- Technical context: PrivacyRequestIncomplete — missing required intake or ops fields (contact email, subject locator, provider ref, rejection reason).
ERR_LLM_001 — AI text provider not configured
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: This AI text provider isn't set up on this server yet. *If you run this deployment, add the provider API key (see README). Otherwise, contact your administrator.*
- Technical context: LlmProviderNotConfigured — GEMINI_API_KEY / OPENAI_API_KEY / ANTHROPIC_API_KEY empty for the requested provider. Raised before any credits are held.
ERR_LLM_002 — Text generation failed
- HTTP status: 409
- Severity: error · Display: toast
- User sees: The AI provider couldn't complete this request, and your credit for it has been returned. *Try again. If it keeps failing, switch providers or contact support with the code below.*
- Technical context: LlmCallFailed — the provider call errored or returned no text. The credit hold is released before this is raised, which is what makes the 'credit returned' promise honest. A FAILED llm_calls row records the provider error verbatim.
- ⚠ Ops signal: Sustained rate on one provider = provider outage or quota exhaustion — check the provider status page and API quota.
ERR_LLM_003 — Text completion not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that text completion. *Head back to your completions list — it may have been removed.*
- Technical context: LlmCallNotFound — llm call id missing for this org, or a non-UUID id was requested on the poll endpoint.
ERR_BILL_001 — Billing not configured
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: Payments aren't set up on this server yet. *If you run this deployment, add your Stripe keys (see README). Otherwise, contact your administrator.*
- Technical context: BillingNotConfigured — STRIPE_SECRET_KEY is empty. Expected in fresh dev environments; in production it means env misconfiguration.
ERR_BILL_002 — Payment provider unreachable
- HTTP status: 502
- Severity: critical · Display: toast · Auto-retry: 2× after 2000ms
- User sees: We couldn't reach our payment provider just now. You have not been charged. *Wait a moment and try again. Your credits and data are unaffected.*
- Technical context: StripeUnavailable — Stripe API connection error / 5xx / rate limit during checkout, portal, or customer creation. Log the stripe request id. 'You have not been charged' is the critical UX line — payment errors create disproportionate anxiety.
- ⚠ Ops signal: More than a handful in 5 minutes = Stripe incident or egress problem — check status.stripe.com.
ERR_BILL_003 — Plan not purchasable
- HTTP status: 409
- Severity: info · Display: toast
- User sees: That plan can't be purchased directly. *Buy a credit pack on the Billing page instead.*
- Technical context: PlanNotPurchasable — retired with subscription plans (credit packs are the only purchase now). Kept for old cached bundles.
ERR_BILL_004 — No billing account
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: This organization doesn't have a billing account yet. *Buy a credit pack first — that sets up billing automatically.*
- Technical context: NoBillingAccount — Customer Portal requested before any checkout created a Stripe customer.
ERR_BILL_005 — Billing update processing
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: Your billing update is still processing. *Give it a minute, then refresh. If nothing changes after a few minutes, contact support with the code below.*
- Technical context: BillingSyncPending — retired with subscription plans (there is no local subscription cache anymore). Kept for old cached bundles.
ERR_BILL_006 — Credit pack not purchasable
- HTTP status: 409
- Severity: warning · Display: toast
- User sees: That credit pack can't be purchased right now. *Pick another pack, or contact your administrator if none work.*
- Technical context: PackNotPurchasable — a credit pack was requested whose Stripe price id is unset (STRIPE_PRICE_CREDITS_*).
ERR_SRV_001 — Internal server error
- HTTP status: 500
- Severity: critical · Display: toast
- User sees: Something went wrong on our end. Your data is safe, and we've been notified. *Try again in a few moments. If it keeps happening, contact support and mention the code shown below.*
- Technical context: Catch-all for unhandled exceptions. The handler logs the full traceback against the error_id and returns ONLY this envelope — never exception text. 'Your data is safe' is honest because get_db rolls back the transaction on failure.
- ⚠ Ops signal: Any sustained rate is an incident. Fingerprint by error_id lookup, not by user reports.
ERR_SRV_002 — Request timed out
- HTTP status: 504
- Severity: error · Display: toast · Auto-retry: 2× after 2000ms
- User sees: This is taking longer than expected. *Wait a moment and try again — your previous attempt may still finish on its own.*
- Technical context: Upstream/gateway timeout (frontend-mapped from bodyless 502/504). Retrying a mutation is safe ONLY because the api client attaches an Idempotency-Key and reuses it on retry.
ERR_SRV_003 — Maintenance in progress
- HTTP status: 503
- Severity: warning · Display: page
- User sees: We're doing some quick maintenance and will be right back. *Nothing to fix on your end — this page will refresh itself when we're done.*
- Technical context: Deliberate maintenance mode or healthcheck-failed state at the proxy (frontend-mapped from a bodyless 503). The frontend shows a full-page takeover and polls /api/health with backoff, reloading when it recovers.
ERR_SRV_004 — Duplicate request in progress
- HTTP status: 409
- Severity: info · Display: toast
- User sees: We're still working on your previous attempt at this. *Give it a few seconds — the first attempt should finish on its own.*
- Technical context: Idempotency middleware: a second request arrived with the same Idempotency-Key while the first was still in flight. Usually a double-click or an aggressive client retry.
ERR_KEY_001 — API key not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We couldn't find that API key. *Head back to the API Keys page — it may have been revoked.*
- Technical context: ApiKeyNotFound — API key id missing for this org (repos filter by organization_id, so cross-tenant ids land here by design).
ERR_PROP_001 — Property not found
- HTTP status: 404
- Severity: info · Display: toast
- User sees: No property records found for this person. *Try searching by address instead, or check if the county is in our coverage area.*
- Technical context: PropertyNotFound — no ownership links exist for the given consumer_key in the property_links dataset.
ERR_PROP_002 — County not covered
- HTTP status: 404
- Severity: info · Display: toast
- User sees: We don't have property data for this county yet. *Check our coverage map at /properties/coverage to see which counties are available.*
- Technical context: CountyNotCovered — the requested FIPS code has no property data in the properties dataset.
ERR_PROP_003 — Could not parse address
- HTTP status: 400
- Severity: warning · Display: toast
- User sees: We couldn't understand that address. Please check the format and try again. *Make sure you've entered at least a street name and either a state or zip code.*
- Technical context: AddressParseError — address normalization failed or insufficient address components for a property search.
ERR_REF_001 — Referral limit reached
- HTTP status: 409
- Severity: info · Display: toast
- User sees: Your organization has already earned the maximum number of company-referral bonuses. *You can keep sharing CoverFi, but additional referrals won't earn bonus credits.*
- Technical context: ReferralLimitReached — SendCompanyReferral blocked because the org's paid org-referral count is at the configured cap.
ERR_REF_002 — That's a teammate, not a referral
- HTTP status: 400
- Severity: info · Display: field
- User sees: That address is on your own company's domain, so it counts as a teammate, not a company referral. *Invite them from the Members page instead — teammate invites earn their own bonus.*
- Technical context: SameCompanyReferral — POST /orgs/{org_id}/referrals/invitations with a target email on the org's claimed email domain.
ERR_NET_001 — You're offline
- HTTP status: — (frontend-only)
- Severity: info · Display: banner · Auto-retry: 2× after 1500ms
- User sees: We can't reach the internet right now. *Check your connection — we'll retry automatically, and anything you typed is still here.*
- Technical context: FRONTEND-ONLY: fetch() rejected (TypeError) — no response received, so no backend envelope exists. Synthesized by the api client. In dev, CORS failures also surface as TypeError — check the browser console.