Genace

generation API error schema validation: keep status and recovery fields

A strict client should reject malformed error data without erasing the HTTP response that carried it. If a proxy returns HTML with status 502, a JSON exception is not the most useful incident record. Keep transport status, parsing outcome, and validated gateway fields separate so your application can explain what is known and what remains uncertain.

Define a minimum error envelope

Genace’s HTTP error serializer produces an error object with type, code, and message. It can also include param, upstream request identifier, and a local job identifier. Validate the required strings while preserving optional fields only when their types are appropriate. The following helper consumes already parsed data and performs no network operation.

export function gatewayError(value) {
  const error = value?.error;
  if (!error || typeof error !== 'object') return null;
  if (!['type', 'code', 'message'].every(
    (field) => typeof error[field] === 'string'
  )) return null;
  return {
    type: error.type,
    code: error.code,
    message: error.message,
    ...(typeof error.job_id === 'string' ? { jobId: error.job_id } : {}),
    ...(typeof error.param === 'string' ? { param: error.param } : {}),
    ...(typeof error.upstream_request_id === 'string'
      ? { upstreamRequestId: error.upstream_request_id } : {}),
  };
}

This is a local normalized view. Save the reviewed original envelope separately when required for support, rather than claiming the renamed properties are returned by the API. Avoid exposing raw response bodies to end users or logging unbounded content.

Preserve HTTP evidence outside the schema

Represent a response with fields for HTTP status, content type, parse result, and optional validated error. When validation fails, retain the status and a safe diagnostic category such as unexpected body. Do not downgrade a 401 into a generic render failure merely because the body was not the JSON shape you expected.

Read the body once. A logger that consumes it first can create a second failure unrelated to the gateway. Bound diagnostic storage and redact sensitive messages according to your application’s policy. Signed media URLs and prompt content can appear in operational data even when a secret key does not.

Preserve the local job reference on submission failure

For HTTP 502 with UPSTREAM_SUBMISSION_FAILED, the serializer can include error.job_id. Save that local ID and inspect GET /api/v1/jobs/{id}. The snapshot uses id, not the HTTP error’s nested name. Its error object is a job diagnostic object and does not require the same type field as an HTTP ApiError.

Refund settlement can still be pending on that failed snapshot. Check credits_actual and credit history rather than assuming the 502 itself proves a completed refund. The new submission compensation path does not turn every HTTP 500 or lost connection into an automatically reconciled failure.

Exercise the ambiguous branches

Test missing error objects, numeric codes, null messages, HTML bodies, and valid envelopes with optional fields absent. Test a normal failed job snapshot separately from an HTTP error envelope. Confirm the client retains both the HTTP status and known local job ID without inventing an upstream identifier.

Finally, assert malformed responses cannot automatically trigger a new POST. A status request can be repeated against a known ID under your read retry policy, while a new generation remains an explicit budget decision.

Continue with failed job interpretation, single body parsing, and trace correlation.

Continue with code and integration

Where these facts come from

  • Editorial keyword hypothesis; search volume not measured
  • codebase: src/ai/api/errors.ts
  • codebase: src/ai/jobs/http.ts
  • codebase: src/ai/jobs/service.ts