overleaf/overleaf · error · InvalidInstitutionalEmailError
InvalidInstitutionalEmailError
Error message
InvalidInstitutionalEmailError
What it means
InvalidInstitutionalEmailError is thrown when the affiliations API rejects a new institutional affiliation with HTTP 422, meaning the supplied email address is not a valid institutional (university-domain) email. It wraps the upstream error via withCause so the original API message is preserved.
Source
Thrown at services/web/app/src/Features/Institutions/InstitutionsAPI.mjs:229
try {
await _affiliationRequestFetchNothing({
method: 'POST',
path: `/api/v2/users/${userId.toString()}/affiliations`,
body: {
email,
university,
department,
role,
confirmedAt,
entitlement,
rejectIfBlocklisted,
},
defaultErrorMessage: "Couldn't create affiliation",
})
} catch (error) {
if (error.info?.status === 422) {
throw new InvalidInstitutionalEmailError(error.message).withCause(error)
}
throw error
}
if (!university) {
return
}
// have notifications delete any ip matcher notifications for this university
try {
await NotificationsBuilder.promises
.ipMatcherAffiliation(userId.toString())
.read(university.id)
} catch (err) {
// log and ignore error
logger.err({ err }, 'Something went wrong marking ip notifications read')
}
}View on GitHub (pinned to 28ad3b03b7)
Solutions
- Have the user enter an email on a domain owned by the institution
- Check the institution's confirmed email-domain settings in the institutions admin data
- Inspect error.cause / error.message for the specific 422 reason from the affiliations API
- If the domain is legitimately institutional, update the institution's email-domain allowlist
Example fix
// before
await addAffiliation(institutionId, { email: user.email })
// after
if (!user.email.endsWith('@university.edu')) {
throw new InvalidInstitutionalEmailError(`${user.email} is not institutional`)
}
await addAffiliation(institutionId, { email: user.email }) Defensive patterns
Strategy: validation
Validate before calling
function isLikelyInstitutionalEmail(email, allowedDomains) {
const domain = email.split('@')[1]?.toLowerCase()
return !!domain && allowedDomains.includes(domain)
}
if (!isLikelyInstitutionalEmail(email, institutionDomains)) throw new Error('not institutional') Type guard
function has422Info(e) {
return typeof e === 'object' && e !== null && e.info?.status === 422
} Try / catch
try {
await addAffiliation(institutionId, { email, role, department })
} catch (error) {
if (error instanceof InvalidInstitutionalEmailError) {
notifyUser('Please use your university email address')
} else throw error
} Prevention
- Show only institution-owned domains in the email input UI hint
- Validate domain against the institution's confirmed domains client-side
- Surface the upstream 422 message to the user, not a generic failure
When it happens
Trigger: Calling addAffiliation with an email that the affiliations backend refuses with status 422 (e.g. free-mail domains like gmail.com, malformed address, or a domain not recognized as the university's).
Common situations: User typed a personal email instead of their university address; institution's claimed email domains are misconfigured in the institutions service; SSO/metadata changes invalidated previously accepted domains.
Related errors
- doc updater could not load requested ops
- error getting affiliations from v1
- ${options.defaultErrorMessage}: ${status}
- invalid email --${flag}=${raw}
- No institution id
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/254751a27ec526c7.
Report an issue: GitHub.