toeverything/AFFiNE · error · InvalidCheckoutParameters
invalid_checkout_parameters
invalid_checkout_parameters
Error message
Invalid checkout parameters provided.
What it means
Thrown by SubscriptionService.checkout when CheckoutExtraArgs.safeParse(args) fails. CheckoutExtraArgs is a zod union of UserSubscriptionCheckoutArgs, WorkspaceSubscriptionCheckoutArgs, and SelfhostTeamCheckoutArgs, so the extra args must structurally match the plan's expected shape (e.g. team checkout needs workspace args, selfhost team needs license/seat args).
Source
Thrown at packages/backend/server/src/plugins/payment/service.ts:144
params: z.infer<typeof CheckoutParams>,
args: z.infer<typeof CheckoutExtraArgs>
) {
const { plan, recurring, variant } = params;
if (
env.namespaces.canary &&
env.prod &&
args.user &&
!this.feature.isStaff(args.user.email)
) {
throw new ActionForbidden();
}
const manager = this.select(plan);
const result = CheckoutExtraArgs.safeParse(args);
if (!result.success) {
throw new InvalidCheckoutParameters();
}
return manager.checkout(
{
plan,
recurring,
variant: variant ?? null,
},
params,
args
);
}
async cancelSubscription(
identity: z.infer<typeof SubscriptionIdentity>,
idempotencyKey?: string
): Promise<Subscription> {
this.assertSubscriptionIdentity(identity);View on GitHub (pinned to b4c8548c09)
Solutions
- Mirror the server's CheckoutExtraArgs union in the client and zod-parse args before calling checkout; use safeParse to surface which union branch failed.
- Match args shape to plan: team -> workspace checkout args, pro/ai -> user checkout args, selfhostedteam -> selfhost team args.
- Regenerate/refresh client types from the backend schema after upgrading the payment plugin.
Example fix
// before
await svc.checkout(
{ plan: 'team', recurring: 'monthly' },
{ userId: user.id } // wrong union branch for team
);
// after
await svc.checkout(
{ plan: 'team', recurring: 'monthly' },
{ workspaceId: workspace.id } // matches WorkspaceSubscriptionCheckoutArgs
); Defensive patterns
Strategy: validation
Validate before calling
import { z } from 'zod';
const CheckoutArgs = z.union([
z.object({ userId: z.string() }),
z.object({ workspaceId: z.string() }),
z.object({ licenseId: z.string(), seats: z.number().int().min(1) }), // mirror selfhost args
]);
const parsed = CheckoutArgs.safeParse(args);
if (!parsed.success) throw new Error(parsed.error.issues.join('; '));
await svc.checkout({ plan, recurring, variant }, parsed.data); Type guard
function matchesPlanArgs(plan: string, args: unknown): boolean {
if (plan === 'team') return !!args && typeof (args as any).workspaceId === 'string';
if (plan === 'selfhostedteam') return !!args && 'licenseId' in (args as object);
if (plan === 'pro' || plan === 'ai') return !!args && 'userId' in (args as object);
return false;
} Try / catch
catch (e) { if (gqlErrorCode(e) === 'invalid_checkout_parameters') { const r = CheckoutArgs.safeParse(args); highlightForm(r.error?.issues); return; } throw e; } Prevention
- Keep the client zod schema in lockstep with the server's CheckoutExtraArgs union.
- Run safeParse client-side before every checkout call and surface issues on the form.
- Add a contract test comparing client and server arg schemas on CI.
When it happens
Trigger: Calling checkout with plan 'team' but user-shaped args (userId instead of workspaceId), or plan 'selfhostedteam' without the required selfhost fields; sending extra/misspelled keys so no union member matches; passing args as a JSON string instead of an object.
Common situations: One generic checkout form reused for all plans; frontend args schema drifted from the server's zod definitions after a backend update; missing idempotency/variant fields newly required.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid config for module [${module}] with key [${key}] Valu
- captcha_verification_failed
- workspace_id_required_to_update_team_subscription
- unsupported_subscription_plan
- action_forbidden
AI-assisted analysis of toeverything/AFFiNE@b4c8548c09 (2026-08-18).
Data as JSON: /api/errors/a5ae4d6a7e400be8.
Report an issue: GitHub.