antiwork/gumroad · error · ResponseError

No recovery codes were generated. Please try again.

Error message

No recovery codes were generated. Please try again.

What it means

Thrown when recovery-code regeneration succeeded at the HTTP level (response.ok, success:true) but the payload's recovery_codes array is missing or empty. This is a contract violation between controller and client: the endpoint reported success without delivering codes, and the client refuses to overwrite the UI with an empty list. It is intentionally a different message from the generic failure so this drift is visible in support reports.

Source

Thrown at app/javascript/pages/Settings/Password/Show.tsx:111

  const handleRegenerateRecoveryCodes = asyncVoid(async () => {
    setRegenerating(true);

    try {
      const response = await request({
        url: Routes.regenerate_recovery_codes_settings_totp_path(),
        method: "POST",
        accept: "json",
      });
      const result = typia.assert<{ success: boolean; recovery_codes?: string[]; error_message?: string }>(
        await response.json(),
      );
      if (!response.ok || !result.success) {
        throw new ResponseError(result.error_message ?? "Sorry, something went wrong. Please try again.");
      }

      if (!result.recovery_codes?.length) {
        throw new ResponseError("No recovery codes were generated. Please try again.");
      }
      setRegeneratedCodes(result.recovery_codes);
    } catch (e) {
      assertResponseError(e);
      showAlert(e.message, "error");
    } finally {
      setRegenerating(false);
    }
  });

  return (
    <SettingsLayout currentPage="password" pages={props.settings_pages}>
      <form onSubmit={handleSubmit}>
        <FormSection header={<h2>Change password</h2>}>
          {requireOldPassword ? (
            <Fieldset>
              <FieldsetTitle>
                <Label htmlFor={`${uid}-old-password`}>Old password</Label>

View on GitHub (pinned to afeacbd394)

Solutions

  1. Retry the regeneration — transient generation failures often resolve on a second attempt.
  2. If it reproduces, inspect the response body: success:true plus empty codes is a server contract bug, not user error.
  3. Maintainers: fix the controller to always return a non-empty recovery_codes on success, or success:false with error_message.
  4. Add an endpoint test asserting recovery_codes is present and non-empty for every success response.

Example fix

# Rails controller, before
render json: { success: true }
# after
codes = generate_recovery_codes
if codes.empty?
  render json: { success: false, error_message: "Could not generate codes." }, status: :internal_server_error
else
  render json: { success: true, recovery_codes: codes }
end
Defensive patterns

Strategy: validation

Validate before calling

const hasRecoveryCodes = (body: { success: boolean; recovery_codes?: string[] }): boolean =>
  body.success && Array.isArray(body.recovery_codes) && body.recovery_codes.length > 0;

Type guard

type RecoveryCodesResponse =
  | { success: true; recovery_codes: [string, ...string[]] }
  | { success: false; error_message: string };

const isUsableRecoveryCodesResponse = (b: { success: boolean; recovery_codes?: string[] }): b is RecoveryCodesResponse =>
  b.success === false || (Array.isArray(b.recovery_codes) && b.recovery_codes.length > 0);

Try / catch

try {
  const result = typia.assert<{ success: boolean; recovery_codes?: string[]; error_message?: string }>(await response.json());
  if (!response.ok || !result.success) throw new ResponseError(result.error_message ?? GENERIC);
  if (!result.recovery_codes?.length) throw new ResponseError("No recovery codes were generated. Please try again.");
  setRegeneratedCodes(result.recovery_codes);
} catch (e) {
  assertResponseError(e);
  showAlert(e.message, "error");
}

Prevention

When it happens

Trigger: POST regenerate_recovery_codes_settings_totp_path returns { success: true } with recovery_codes: [] or the key omitted entirely — controller bug, partial serialization, or an intermittent generation path that yields no codes.

Common situations: Rails serializer changes dropping the field, caching layers stripping payloads, tests stubbing the endpoint with success-only fixtures; users click 'Regenerate codes' and get this error with no codes shown.

Related errors


AI-assisted analysis of antiwork/gumroad@afeacbd394 (2026-08-21). Data as JSON: /api/errors/4b92562df18eaeb8. Report an issue: GitHub.