# What Happens on Generation Reservation Failure: Error Handling in awesome-gpt-image-2

> Understand generation reservation failures in awesome-gpt-image-2. Learn how the system rolls back credits to prevent charges on failed requests.

- Repository: [苍何/awesome-gpt-image-2](https://github.com/freestylefly/awesome-gpt-image-2)
- Tags: error-handling
- Published: 2026-09-04

---

**When an image generation reservation fails, the system automatically rolls back the user's usage credits by invoking the `release_generation_reservation` Supabase RPC with an appropriate error code, ensuring no charges are incurred for failed or incomplete requests.**

In the `freestylefly/awesome-gpt-image-2` repository, the image generation pipeline uses a reservation system to manage user credits. When upstream providers like Apimart fail to complete a request, the codebase implements a robust error handling mechanism that detects failures, translates error codes, and releases reservations to restore the user's credit balance.

## Detecting Generation Failures in the API Handler

The primary failure detection occurs in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js). The code wraps the upstream submission in a try-catch block that intercepts any errors from `submitApimartGeneration`.

When an exception occurs, the catch block (lines 61-75) immediately initiates the rollback process:

```js
} catch (error) {
  const errorCode = publicErrorCode(error);
  await releaseReservation(auth.client, reservation.reservationId, errorCode);
  // ...
}

```

This ensures that no pending reservation remains active if the generation request cannot be fulfilled.

## Mapping Private Errors to Public Error Codes

Before releasing the reservation, the system normalizes error messages through the `publicErrorCode` function (lines 66-71). This abstraction prevents leaking internal provider details while categorizing failures:

```js
export function publicErrorCode(error) {
  if (error?.code === 'APIMART_RATE_LIMITED') return 'UPSTREAM_BUSY';
  // ...
  return 'GENERATION_FAILED';
}

```

**Supported error mappings** include:

- `APIMART_RATE_LIMITED` → `UPSTREAM_BUSY`
- Default fallback → `GENERATION_FAILED`

## Releasing the Reservation and Restoring Credits

The `releaseReservation` function (lines 51-58) performs the actual rollback by invoking a Supabase RPC. This updates the reservation status to *released* and records the failure reason:

```js
async function releaseReservation(client, reservationId, errorCode) {
  if (!reservationId) return;
  const { error } = await client.rpc('release_generation_reservation', {
    p_reservation_id: reservationId,
    p_error_code: errorCode || 'GENERATION_FAILED'
  });
  // ...
}

```

The `release_generation_reservation` stored procedure restores the user's credit balance and marks the reservation as released, making the failure state visible to the client.

## Handling Failures in Provider Callbacks

An alternative failure path exists in [`api/generation/callback.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generation/callback.js) for asynchronous provider callbacks. When the provider calls the `/api/generation` endpoint, the code first validates the reservation status (lines 29-31):

```js
const reservation = await findReservation(client, taskId);
if (!reservation) return { state: 'ignored' };
if (reservation.status !== 'pending') return { state: 'duplicate' };
await settle(client, reservation, verifiedTask);

```

If the reservation is not in *pending* status, the callback is treated as a duplicate. Otherwise, the system proceeds to settlement.

### Settlement Logic and Final State Resolution

The `settlePlatformGeneration` function in [`api/_lib/generation.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/generation.js) (lines 71-84) handles the final state transition. If the task status is anything other than *completed*, it releases the reservation:

```js
if (task.status === 'completed' && task.image) {
  // complete reservation
} else {
  await client.rpc('release_generation_reservation', {
    p_reservation_id: reservation.id,
    p_error_code: task.errorCode || 'GENERATION_FAILED'
  });
}

```

This ensures that failed, cancelled, or errored tasks all trigger the credit rollback mechanism.

## Summary

Key takeaways from the generation reservation failure handling:

- **Automatic rollback**: Every failure path calls `release_generation_reservation` to restore user credits
- **Error normalization**: Internal provider errors are mapped to public codes like `UPSTREAM_BUSY` or `GENERATION_FAILED`
- **Dual protection**: Both synchronous try-catch blocks and asynchronous callback handlers implement release logic
- **Idempotent handling**: The callback system prevents duplicate processing by checking reservation status before settlement
- **Transparency**: Error codes are stored with the reservation, allowing clients to understand why generation failed

## Frequently Asked Questions

### What error codes does the system return on generation reservation failure?

The system returns normalized error codes such as `UPSTREAM_BUSY` for rate limiting or `GENERATION_FAILED` for generic errors. These are stored in the reservation record via the `p_error_code` parameter of the `release_generation_reservation` RPC, ensuring clients receive consistent error messaging regardless of the upstream provider's response.

### How does the system ensure user credits are restored after a failure?

Credits are restored through the `release_generation_reservation` Supabase RPC call, which is triggered by either the `releaseReservation` function in the main handler or the `settlePlatformGeneration` function in the callback processing. Both pathways update the reservation status to *released* and revert the credit deduction made during reservation creation.

### What happens if the provider sends a duplicate callback for a failed generation?

In [`api/generation/callback.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generation/callback.js), the system checks the reservation status before processing. If the status is not *pending*, the callback returns `{ state: 'duplicate' }` and ignores the request. This prevents double-releasing reservations or incorrectly updating user credit balances for already-settled transactions.

### Which files contain the core failure handling logic?

The primary failure detection resides in [`api/generate-image.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generate-image.js), while [`api/_lib/generation.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/_lib/generation.js) contains the settlement logic used by both synchronous and asynchronous paths. The callback-specific handling is implemented in [`api/generation/callback.js`](https://github.com/freestylefly/awesome-gpt-image-2/blob/main/api/generation/callback.js), and the database operations are defined in the Supabase migration files that create the `release_generation_reservation` RPC.