n8n-io/n8n · warning · BadRequestError

Invalid payload or URL

Error message

Invalid payload or URL

What it means

A BadRequestError (HTTP 400) from the invitation-acceptance flow (processInvitationAcceptance). After loading the two users by inviterId and inviteeId, if fewer than 2 users are found the token is treated as invalid and the request is rejected. It signals that the invite link/token references users that do not exist in the DB — typically a tampered, expired, or already-consumed invite.

Source

Thrown at packages/cli/src/controllers/invitation.controller.ts:117

		lastName: string,
		password: string,
		req: AuthlessRequest,
		res: Response,
	): Promise<Awaited<ReturnType<UserService['toPublic']>>> {
		const users = await this.userRepository.find({
			where: [{ id: inviterId }, { id: inviteeId }],
			relations: ['role'],
		});

		if (users.length !== 2) {
			this.logger.debug(
				'Request to fill out a user shell failed because the inviter ID and/or invitee ID were not found in database',
				{
					inviterId,
					inviteeId,
				},
			);
			throw new BadRequestError('Invalid payload or URL');
		}

		const invitee = users.find((user) => user.id === inviteeId) as User;

		if (invitee.password) {
			this.logger.debug(
				'Request to fill out a user shell failed because the invite had already been accepted',
				{ inviteeId },
			);
			throw new BadRequestError('This invite has been accepted already');
		}

		invitee.firstName = firstName;
		invitee.lastName = lastName;
		invitee.password = await this.passwordUtility.hash(password);

		const updatedUser = await this.userRepository.save(invitee, { transaction: false });

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Request a fresh invite from an admin; the old token's referenced users no longer exist.
  2. Ensure the invitee/inviter user rows still exist in the user table (Admin UI > Users).
  3. Confirm the instance URL matches the one that issued the invite (tokens are instance-specific).
  4. Regenerate the invite and use the new link promptly.
Defensive patterns

Strategy: try-catch

Validate before calling

// Tokens are opaque JWTs; you cannot fully validate client-side, but sanity-check structure.
function looksLikeInviteToken(t: unknown): boolean {
  return typeof t === 'string' && t.split('.').length === 3;
}
if (!looksLikeInviteToken(token)) throw new Error('Malformed invite token');

Try / catch

try {
  await api.post('/accept-invitation', { token, firstName, lastName, password });
} catch (e) {
  if (e.response?.status === 400 && /Invalid payload or URL/i.test(e.response.data.message)) {
    notify('This invite is no longer valid — request a new one.');
    return;
  }
  throw e;
}

Prevention

When it happens

Trigger: POST to the acceptance endpoint with a token whose decoded inviterId or inviteeId no longer matches any user row — e.g. the invitee or inviter was deleted, the token was fabricated, or the DB was reset after the invite was sent.

Common situations: User clicks an old invite link after the inviter left and their account was deleted; DB restore/rollback that dropped user rows; token forgery; invite generated on a different instance (wrong DB).

Related errors


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/b43871fceb4cf9df. Report an issue: GitHub.