Skip to content

Troubleshooting

Every EdgeKit ID refusal answers { "error": { "code", "message" } }. The codes are in the error code reference. Problems with cookies, origins and the /edgekit/ mount are in First-party mount troubleshooting.

Sending answers 200 whether or not a user holds the address, so a 200 does not prove an email went out. Check:

  • The address. A typo gets the same 200.
  • A 429. Three sign-in emails to one address in a minute is the limit, counting codes, links and address-change codes. Wait a minute.
  • The sender. Emails come from EdgeKit’s own address until your organization sets its transactional mail settings; a spam filter may treat the two differently. See Site settings.

A 500 internal_error means EdgeKit could not send the email. Nothing was sent, and the user may try again.

Sign-in answers 404 not_found: “No route matches this path.”

Section titled “Sign-in answers 404 not_found: “No route matches this path.””

The route is closed at this site:

  • The site is external_only, or dual without EdgeKit sign-in turned on. GET /v1/id/config shows methods empty and no sign-in in operations.
  • For POST /v1/id/sign-in/google: your organization has no Google client. methods then has no google entry.
  • For POST /v1/id/session/exchange: the site is not dual.
  • The path has a trailing slash, or a different spelling. EdgeKit matches paths exactly.

See Choose who signs users in.

Section titled “The magic link opens a page that answers 404”

The link opens /edgekit/v1/id/magic-link/verify, or /v1/id/magic-link/verify, on the host EdgeKit received the send request on: your tenant host when your forwarder sets Host to it. EdgeKit answers that address 404, and no setting points the link at a page you host, so a magic link cannot be completed today. Offer the email code instead. See Sign in with a magic link.

“That code is not valid.” or “That code has expired. Request a new one.”

Section titled ““That code is not valid.” or “That code has expired. Request a new one.””

400 bad_request. The code is wrong, was already used, or is older than 5 minutes. Each new send mails a new code, so the user should type the code from the newest email.

Message What to do
Too many sign-in emails for this address. Try again in a minute. Wait for Retry-After, 60 seconds.
Too many code attempts for this address. Try again in a minute. Wait 60 seconds. Three attempts a minute per address.
Too many attempts. Request a new code. Three wrong guesses spent this code: send a new one.

The address limits ignore +tags and dots before the @, so variants of one address share the allowance.

422 unprocessable_entity: “Request validation failed.”

Section titled “422 unprocessable_entity: “Request validation failed.””

The body is malformed: an address that is not an email address, a code that is not 6 digits, a field longer than its limit, a callbackURL that is neither a path nor an http(s) URL, or traits that fail their checks. details, when present, says which field.

403 forbidden: “That redirect target is not registered for this site.”

Section titled “403 forbidden: “That redirect target is not registered for this site.””

The magic link’s callbackURL is an absolute URL on an origin not in the site’s Redirect origins. Use a relative path, or add the origin and deploy. A value that is neither a path nor an http(s) URL answers 422 unprocessable_entity instead. See Site settings.

Google answers “That address already has an account. Sign in with an emailed code once, then Google will work.”

Section titled “Google answers “That address already has an account. Sign in with an emailed code once, then Google will work.””

A user already holds the address, and their address is not verified yet, so EdgeKit will not link the Google account to them. One sign-in with an emailed code verifies the address; Google then signs in to that user.

Sign-in succeeds but the next request is anonymous

Section titled “Sign-in succeeds but the next request is anonymous”

The session cookie did not come back. See Sign-in succeeds but the next request is anonymous. On a site the cookie domain does not reach, the user has to sign in there too; see Sessions across your sites.

401 unauthorized: “No user session.” or “This route requires a user session.”

Section titled “401 unauthorized: “No user session.” or “This route requires a user session.””
  • No user session.: the request carries no valid session. In a browser, check that the request goes to your own domain with credentials; from an app, check the Authorization: Bearer token.
  • This route requires a user session.: the request carries an API key in x-api-key. Routes that act on the signed-in user accept the user’s session only.

A user still looks signed in after their session ended

Section titled “A user still looks signed in after their session ended”

GET /v1/id/get-session can answer with an ended session’s user for up to 15 minutes, and decide can keep reading the user for up to an hour after the site’s access cookie was last refreshed. Routes that change the user’s data refuse at once. See How quickly an ended session stops working.

Everyone reads as signed out at an external_only site

Section titled “Everyone reads as signed out at an external_only site”

GET /v1/id/get-session answers two nulls for a missing, expired or invalid credential, with no error. To see why, check the token against what EdgeKit requires:

  • the cookie name is one of the names EdgeKit has for your login, spelled exactly;
  • the cookie is set on your own domain, so it reaches the /edgekit/ mount;
  • alg is the algorithm EdgeKit has, and typ is edgekit-id+jwt;
  • iss matches, and aud is the value EdgeKit gave you for this site, not another site’s;
  • iat is recent: a token older than its age limit is refused even when exp is in the future;
  • it carries email the first time EdgeKit sees the person.

See A token your login signs. At a dual site, POST /v1/id/session/exchange answers the refusal with a code; see The exchange.

A paying user reads as signed out after we connected our login

Section titled “A paying user reads as signed out after we connected our login”

Their credential named an address that already has a user, without email_verified: true. EdgeKit does not link a credential to an existing user on an unverified address, and cannot create a second user with the same address, so the person reads as signed out. Identity › Audience › Observability records it as identity.adoption_refused. Have your login assert email_verified: true for addresses it has proven.

After a failed exchange, GET /v1/id/get-session does not try again in that browser for 5 minutes, and answers signed out meanwhile. A fixed credential takes effect after the pause, or at once through POST /v1/id/session/exchange.

identity_provider_unreachable or identity_provider_rate_limited: your login did not answer in time, or is limiting EdgeKit. Retry after Retry-After. At an external_only site the same failure reads as signed out.

Without Retry-After, sign-in is not fully set up for your organization: contact EdgeKit. With Retry-After, it is a short outage on EdgeKit’s side: retry after it.

A deploy is refused because a feature reads external.*

Section titled “A deploy is refused because a feature reads external.*”

external.* facts exist only at external_only sites. A feature that reads them may cover only such sites, and a feature with no sites listed covers every site. List the feature’s sites, or move it to grants.*, before a site moves to dual. See Step 2.

Magic link is in the methods of at least one site, and the refusal names them. A magic link creates the user without traits, so EdgeKit does not let a trait be required while one is offered. See Required traits and magic links.

A new trait or setting does not show on the sign-up form

Section titled “A new trait or setting does not show on the sign-up form”

GET /v1/id/config and GET /v1/id/traits are cached for up to 5 minutes. Wait, then reload. A sign-in setting EdgeKit changes for a site also needs a deploy.

  • 403 seat_limit_reached, This organization has no free seats.: the user organization is full. The person is listed as a seat refusal for its owners and admins.
  • Otherwise, check that the user is signed in with the invited address, that the address is verified, and that the invitation has not expired or been replaced by a newer one. A sign-in with an emailed code to that address verifies it.

See Let members run their user organization.

The site is dual or external_only, where your login owns the address. Your server pushes the change instead; see Tell EdgeKit about changes in your login.