toeverything/AFFiNE · error · EmailTokenNotFound
email_token_not_found
email_token_not_found
Error message
The email token provided is not found.
What it means
Thrown by sendVerifyChangeEmail when the token argument is falsy. This is a client-precondition failure, distinct from invalid_email_token (185): the mutation was invoked without any token at all, usually because the emailed link did not carry one.
Solutions
- Make sure the callbackUrl passed to sendChangeEmail contains the token placeholder so safeLink injects it
- Check the query param name the page reads matches what the link emits
- Guard client-side: refuse to call the mutation when the token param is missing and show a 'bad link' page
Example fix
// before
await client.request(sendVerifyChangeEmailMutation, { token: params.get('token') ?? '', email, callbackUrl });
// after
const token = params.get('token');
if (!token) throw new Error('Link is missing its token — check the callbackUrl template');
await client.request(sendVerifyChangeEmailMutation, { token, email, callbackUrl }); Defensive patterns
Strategy: validation
Validate before calling
const token = new URLSearchParams(location.search).get('token');
if (!token) {
renderBadLinkPage('This link is missing its token. Request a new email.');
} else {
await client.request(sendVerifyChangeEmailMutation, { token, email, callbackUrl });
} Prevention
- Include the token placeholder in every callbackUrl template
- Use the same query param name in link template and page parser
- Never substitute a default empty string for a missing token argument
When it happens
Trigger: Calling sendVerifyChangeEmail with token: '' or undefined — typically the frontend parsed a URL query param named differently than the link template, or the callbackUrl template omitted the token placeholder so the emailed URL has no token.
Common situations: callbackUrl configured without the token substitution placeholder; router reads params.token but the link uses ?t=; a redirect/SSO wrapper strips query strings; user hand-edited the URL.
Related errors
- same_email_provided
- email_already_used
- action_forbidden
- copilot_doc_not_found
- description must be provided explicitly.
AI-assisted analysis of toeverything/AFFiNE@2af30773ae (2026-08-18).
Data as JSON: /api/errors/352692859c18c9d5.
Report an issue: GitHub.
Appendix: source
Thrown at packages/backend/server/src/core/auth/resolver.ts:182
) {
return await this.auth.prepareSecurityChallenge(
'change_email',
user.id,
this.url.safeLink(callbackUrl),
this.auth.requestSource(context.req)
);
}
@Mutation(() => Boolean)
async sendVerifyChangeEmail(
@CurrentUser() user: CurrentUser,
@Args('token') token: string,
@Args('email') email: string,
@Args('callbackUrl') callbackUrl: string,
@Context() context: GraphqlContext
) {
if (!token) {
throw new EmailTokenNotFound();
}
validators.assertValidEmail(email);
return await this.auth.prepareVerifyChangeEmail(
user.id,
token,
email,
this.url.safeLink(callbackUrl),
this.auth.requestSource(context.req)
);
}
@Mutation(() => Boolean)
async sendVerifyEmail(
@CurrentUser() user: CurrentUser,
@Args('callbackUrl') callbackUrl: string,
@Context() context: GraphqlContext
) {View on GitHub (pinned to 2af30773ae)