decolua/9router · error · Error

A redeem request id is required to consume a Codex reset…

Error message

A redeem request id is required to consume a Codex reset credit.

What it means

consumeCodexRateLimitResetCredit(accessToken, redeemRequestId) requires a redeem request id identifying which reset credit to spend. If redeemRequestId is missing or not a non-empty string, this guard error is thrown before any network call. No credit is consumed in this case.

Solutions

  1. Fetch available credits first (getCodexRateLimitResetCredits) and pass one of the returned credit ids as redeemRequestId
  2. Validate the client request body includes a string redeemRequestId before dispatching to the handler
  3. Coerce/trim the incoming id and reject empty strings client-side
  4. Check the credits response schema — take the correct id field from each credit object

Example fix

// before
await consumeCodexRateLimitResetCredit(token, body.id);
// after
if (typeof body.redeemRequestId !== 'string' || !body.redeemRequestId) {
  return res.status(400).json({ error: 'redeemRequestId is required' });
}
await consumeCodexRateLimitResetCredit(token, body.redeemRequestId);
Defensive patterns

Strategy: validation

Validate before calling

// caller-side validation before invoking
const rid = body?.redeemRequestId;
if (typeof rid !== 'string' || rid.trim() === '') {
  return res.status(400).json({ error: 'redeemRequestId (string) is required' });
}

Type guard

function isValidRedeemId(id) { return typeof id === 'string' && id.trim().length > 0; }

Try / catch

try {
  await consumeCodexRateLimitResetCredit(accessToken, redeemRequestId);
} catch (e) {
  if (e.message.includes('redeem request id')) {
    const credits = await getCodexRateLimitResetCredits(accessToken);
    redeemRequestId = credits.credits[0]?.id; // recover by fetching a valid id
    if (!redeemRequestId) throw new Error('No reset credits available.');
    return consumeCodexRateLimitResetCredit(accessToken, redeemRequestId);
  }
  throw e;
}

Prevention

When it happens

Trigger: The consume handler is invoked without a redeemRequestId, with an empty string, or with a non-string value (e.g. a number or object from an unvalidated request body).

Common situations: Client UI calling the consume POST without first fetching available credits to obtain an id; request body field renamed or omitted; id coerced to a number by JSON handling.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/8016eb7022c98639. Report an issue: GitHub.

Appendix: source

Thrown at open-sse/services/usage/codex.js:186

  const credits = Array.isArray(data?.credits) ? data.credits : [];
  return {
    availableCount: Math.max(0, toFiniteNumber(data?.available_count ?? data?.availableCount, 0)),
    credits: credits.map((credit) => ({
      status: String(credit?.status || "unknown"),
      grantedAt: toIsoDate(credit?.granted_at ?? credit?.grantedAt),
      expiresAt: toIsoDate(credit?.expires_at ?? credit?.expiresAt),
    })),
  };
}

// Consume one Codex rate-limit reset credit (irreversible, spends 1 credit)
export async function consumeCodexRateLimitResetCredit(accessToken, redeemRequestId, proxyOptions = null) {
  if (!accessToken) {
    throw new Error("No Codex access token available. Please re-authorize the connection.");
  }
  if (!redeemRequestId || typeof redeemRequestId !== "string") {
    throw new Error("A redeem request id is required to consume a Codex reset credit.");
  }

  let response;
  let data = null;
  try {
    response = await proxyAwareFetch(CODEX_CONFIG.resetCreditsConsumeUrl, {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${accessToken}`,
        "Accept": "application/json",
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ redeem_request_id: redeemRequestId }),
    }, proxyOptions);

    const text = await response.text();
    data = text ? JSON.parse(text) : null;
  } catch (error) {

View on GitHub (pinned to 90b52e06ff)