BenchmarksStack Ranking
APIsPricingDocsWhite PaperTokenBlogAboutSecurity Demo
Log InGet API Key
Tutorial · 5 min read

H33 Error Handling:
Best Practices for Production

How to properly handle errors and edge cases in H33 integration.

5 min
Setup
Open
Source
SDK
Ready
Production
Grade

Why Error Handling in Crypto APIs Is Security-Critical

In most web applications, a poorly worded error message is an inconvenience. In cryptographic authentication APIs, it is a vulnerability. Every error response your system emits is a signal that an adversary can observe, measure, and exploit. The difference between "Invalid password" and "User not found" tells an attacker whether an account exists. The difference between a 2ms and a 14ms failure tells them whether a decryption key was partially correct. When your API handles fully homomorphic encryption, zero-knowledge proofs, and post-quantum signatures in a single call — computing on encrypted data without decryption — the surface area for information leakage multiplies.

H33's authentication pipeline runs FHE biometric matching, ZKP verification, and Dilithium attestation in under 42 microseconds per auth. At that speed, even microsecond-level timing variance becomes observable over thousands of requests. Defensive error handling is not optional -- it is a core security control.

The Cardinal Rule

Never return different error messages or response times for authentication failures that differ only in which step failed. An attacker who can distinguish "wrong biometric" from "expired token" from "invalid ZKP" can systematically narrow their attack vector.

Common Anti-Patterns That Leak Information

The most dangerous error handling patterns in cryptographic APIs are those that seem helpful during development but become exploitable in production.

Verbose Error Messages

Returning messages like "BFV ciphertext noise budget exhausted at modulus index 2" or "Dilithium signature verification failed: invalid coefficient at position 847" gives an adversary direct insight into your FHE parameter configuration and signature internals. In a harvest-now-decrypt-later scenario, this metadata is exactly what a future quantum attacker needs to reconstruct your parameter choices.

Timing-Based Oracle Attacks

If your API returns a 401 in 3ms when the user ID is wrong but takes 18ms when the biometric match fails (because FHE decryption ran before failing), an attacker can enumerate valid user IDs without ever submitting a valid biometric. This is a classic timing oracle. The fix is constant-time error paths: always run the full authentication pipeline before returning any error, or pad response times to a fixed duration.

Stack Traces in Production

Returning raw stack traces that mention internal module paths (src/fhe/bfv.rs:412 or src/zkp/plookup.rs:89) reveals your exact software architecture. Attackers use this to target known vulnerabilities in specific library versions. Production APIs must strip all internal details from error responses.

HTTP Status Code Mapping for Auth APIs

Choosing the correct HTTP status code is both a semantic and security decision. Using the wrong code leaks information about why a request failed.

Status Meaning When to Use Security Note
401 Unauthorized Invalid API key, expired token, failed biometric Use for ALL authentication failures -- do not distinguish reason
403 Forbidden Valid auth but insufficient permissions or plan tier Only after successful authentication; never for auth failures
429 Too Many Requests Rate limit exceeded Include Retry-After header; do not reveal per-key vs global limit
400 Bad Request Malformed JSON, missing required fields, invalid FHE parameters Safe to describe which field is missing; never describe why a value is wrong
500 Internal Server Error Unexpected failures, panic recovery Generic message only; log full details server-side
503 Service Unavailable Circuit breaker open, maintenance window Include Retry-After; do not reveal which subsystem is down

Structured Error Responses

Every H33 API error response follows a consistent envelope. The error_code is a stable machine-readable identifier that your retry logic can switch on. The message is a safe, human-readable string that never contains internal details. The request_id is a correlation token that maps to full diagnostic data in your server-side logs.

{
  "error": {
    "code": "AUTH_FAILED",
    "message": "Authentication could not be completed.",
    "request_id": "req_7f3a9c2e1b4d",
    "retry_after": null
  }
}

This structure gives developers everything they need to debug (via request_id) without exposing anything an attacker can exploit. The same AUTH_FAILED code is returned whether the failure was a bad API key, an expired session, a biometric mismatch, or a ZKP verification failure.

H33-Specific Error Codes

Error Code HTTP Status Cause Client Action
AUTH_FAILED 401 Any authentication failure Prompt user to re-authenticate
TOKEN_EXPIRED 401 Session or API token past TTL Refresh token or re-authenticate
RATE_LIMITED 429 Per-key or global rate limit hit Backoff per Retry-After header
FHE_PARAM_MISMATCH 400 Ciphertext parameters do not match enrolled template Re-encrypt with correct scheme parameters
PLAN_LIMIT 403 Monthly auth quota exceeded Upgrade plan or wait for billing cycle reset
SERVICE_UNAVAILABLE 503 Internal subsystem degraded Retry with exponential backoff

Retry Strategies: Backoff, Idempotency, and Circuit Breakers

Not all errors should be retried. A 400 (bad request) will never succeed on retry -- the client must fix the input. A 429 or 503 is inherently transient and should be retried with exponential backoff. A 401 from an expired token should trigger a token refresh, not a blind retry.

Exponential Backoff with Jitter

The standard pattern is min(base * 2^attempt + random_jitter, max_delay). Without jitter, thousands of clients that hit a rate limit simultaneously will retry at the same instant, creating a thundering herd. H33 SDKs use a base of 100ms, a max of 30 seconds, and up to 50% jitter.

Idempotency Keys

For enrollment and verification calls, pass an X-Idempotency-Key header. If a network timeout occurs and you retry, H33 will return the cached result of the original request rather than re-executing the operation. This prevents double-enrollment of biometric templates, which would corrupt the FHE ciphertext state.

Circuit Breakers

If your client observes 5 consecutive 5xx errors within 10 seconds, stop sending requests. Open the circuit breaker for 30 seconds, then send a single probe request. If it succeeds, close the breaker and resume. This protects both your application and H33's infrastructure from cascading failures.

Code Examples

Python: Robust H33 Client

import httpx
import time, random, logging

logger = logging.getLogger("h33")

class H33Client:
    RETRYABLE = {429, 500, 502, 503}

    def authenticate(self, user_id: str, template: bytes):
        for attempt in range(4):
            resp = httpx.post(
                "https://api.h33.ai/v1/auth",
                headers={"Authorization": f"Bearer {self.api_key}"},
                json={"user_id": user_id, "template": template.hex()},
            )
            if resp.status_code == 200:
                return resp.json()

            error = resp.json().get("error", {})
            code = error.get("code")

            # Non-retryable errors: stop immediately
            if resp.status_code not in self.RETRYABLE:
                logger.warning("Auth failed",
                    extra={"request_id": error.get("request_id")})
                raise AuthError(code)

            # Exponential backoff with jitter
            delay = min(0.1 * (2 ** attempt) + random.uniform(0, 0.05), 30)
            time.sleep(delay)

        raise AuthError("MAX_RETRIES_EXCEEDED")

Node.js: Retry with Circuit Breaker

const RETRYABLE = new Set([429, 500, 502, 503]);
let failures = 0, circuitOpen = false, circuitTimer = null;

async function h33Authenticate(userId, template) {
  if (circuitOpen) throw new Error("CIRCUIT_OPEN");

  for (let attempt = 0; attempt < 4; attempt++) {
    const res = await fetch("https://api.h33.ai/v1/auth", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${apiKey}`,
        "Content-Type": "application/json",
        "X-Idempotency-Key": crypto.randomUUID(),
      },
      body: JSON.stringify({ user_id: userId, template }),
    });

    if (res.ok) { failures = 0; return res.json(); }

    const { error } = await res.json();

    // Non-retryable: surface error code, never internal details
    if (!RETRYABLE.has(res.status)) throw new Error(error?.code);

    // Trip circuit breaker after consecutive failures
    if (++failures >= 5) {
      circuitOpen = true;
      circuitTimer = setTimeout(() => { circuitOpen = false; }, 30000);
    }

    const delay = Math.min(100 * 2 ** attempt + Math.random() * 50, 30000);
    await new Promise(r => setTimeout(r, delay));
  }
}

Logging Best Practices: What to Log vs. What to Redact

Server-side logs are your primary diagnostic tool when a request_id comes in from a customer support ticket. But cryptographic systems process data that must never appear in logs, regardless of log level or retention policy.

Never Log These Values

API keys and bearer tokens -- log only the last 4 characters for correlation. Biometric templates -- not even hashed; the hash itself is sensitive. FHE ciphertexts and private keys -- not even truncated. ZKP witness data -- the witness is the secret the proof protects. Dilithium/Kyber private key material -- catastrophic if leaked.

What you should log: request IDs, user IDs, timestamps, HTTP status codes, error codes (the safe ones), response latency, and the specific pipeline stage that failed (as an enum, not a message). This gives you full observability without any secret exposure.

Monitoring and Alerting on Error Rates

Set up threshold-based alerts on your error rates, segmented by error code. A sudden spike in AUTH_FAILED across many distinct user IDs could indicate a credential stuffing attack. A spike in FHE_PARAM_MISMATCH likely means a client SDK was updated with incompatible parameters. A sustained increase in 429 responses means you are either under attack or approaching organic capacity limits.

Key Takeaway

Error handling in cryptographic APIs is not about developer convenience -- it is about closing information channels. Every error message, every timing difference, every status code distinction is a potential signal to an adversary. Design your error paths with the same rigor you apply to your encryption parameters: assume the attacker sees everything, and give them nothing.

Ready to Go Quantum-Secure?

Start protecting your users with post-quantum authentication today. 1,000 free auths, no credit card required.

Get Free API Key →

Build With Post-Quantum Security

Enterprise-grade FHE, ZKP, and post-quantum cryptography. One API call. Sub-millisecond latency.

Get Free API Key → Read the Docs
Free tier · 10,000 API calls/month · No credit card required
Verify It Yourself