Skip to content

Prevent expired invitations from silently failing and blocking future re-invites - #805

Merged
JoseSzycho merged 4 commits into
mainfrom
802-an-expired-invitation-silently-fails-then-blocks-the-person-forever
Sep 25, 2026
Merged

JoseSzycho merged 4 commits into
mainfrom
802-an-expired-invitation-silently-fails-then-blocks-the-person-forever

Conversation

@JoseSzycho

Copy link
Copy Markdown
Contributor

What this changes

When someone lets a join invitation to an organization lapse, two things used to go wrong — and both could leave a person stuck in a situation they couldn't fix on their own:

  1. Accepting a late invitation looked like it worked, but did nothing. If a person tried to accept an invitation after it had expired, the system recorded the acceptance without ever making them a member, and didn't tell them anything was wrong. They believed they had joined the organization, but they hadn't. The invitation just sat there as a dead record.

  2. A dead invitation could block future invitations forever. Because any existing invitation — expired, declined, or otherwise finished — counted as a duplicate, an organization that wanted to invite the same person again was told "Duplicate value" and couldn't. One lapsed invitation could block a re-invite for good.

Why the bugs were there

Both symptoms came from the invite flow trusting an invitation's recorded state and never double-checking whether the invitation was still actually valid at the moment it was used:

  • On acceptance, the system recorded the state without confirming the invitation was still live. When the invitation had already lapsed, the acceptance was recorded but the membership was never granted — silently.

  • On re-invite, the duplicate check treated any existing invitation as a conflict, whether or not it was still live and pending. A rule meant to stop someone from being double-invited at the same time was also blocking legitimate fresh invitations once an older one had finished its life.

What we changed

  • Accepting an expired invitation is now rejected with a clear message. The person is told the invitation has expired and they should ask for a new one — instead of a silent success that grants nothing.
  • Only a live, pending invitation blocks a re-invite. An expired, declined, or otherwise finished invitation no longer stands in the way. An organization can invite a person again any time a previous invitation is no longer outstanding.
  • An expired invitation never creates a membership. There is no backdoor path from an old acceptance record into a membership — the invitation must be valid at the moment it is used.

What else we improved

  • A comprehensive end-to-end test suite now exercises the whole invitation lifecycle: accepting after expiry (must be rejected), re-inviting after expiry, re-inviting after a decline, blocking a genuine duplicate while an invitation is live, and the happy path where accepting a live invitation grants membership and removes the invitation.
  • Every invitation's email is verified. The suite confirms the invitation email is actually created and addressed to the right person, so we know the invitee really was notified.
  • Hardened the test infrastructure itself. While running the suite we found and fixed two test-side issues that could make the tests fail for the wrong reasons — an assertion that never matched, and test fixtures being picked up as a second, competing test run. The suite now runs cleanly and deterministically.

Outcome

No scenario leaves a person unable to join an organization. If an invitation lapses, the person gets a clear reason and the organization can simply invite them again. If an invitation is live, the person can accept it and become a member, exactly as they expect.

Closes #802

@JoseSzycho JoseSzycho linked an issue Sep 24, 2026 that may be closed by this pull request
4 tasks
@JoseSzycho

Copy link
Copy Markdown
Contributor Author

up!

@JoseSzycho

Copy link
Copy Markdown
Contributor Author

@mattdjenkinson I see you updated the branch against main. The e2e tests are green ! 🚀

@JoseSzycho
JoseSzycho merged commit 9ea0679 into main Sep 25, 2026
5 checks passed
@JoseSzycho
JoseSzycho deleted the 802-an-expired-invitation-silently-fails-then-blocks-the-person-forever branch September 25, 2026 15:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

An expired invitation silently fails, then blocks the person forever

2 participants