ory/kratos · warning

verification requested for unknown address

Error message

verification requested for unknown address

What it means

ErrUnknownAddress in link/sender.go is a 404-style herodot error raised when a recovery or verification flow requests a send to an address that does not correspond to any known identity. It is deliberately generic to prevent account enumeration (the code package exposes an equivalent `recovery requested for unknown address` variant).

Solutions

  1. Show the user a generic 'if the address exists we sent an email' message (the API already returns this to avoid enumeration)
  2. Verify the address used matches an existing, active identity's verifiable address in the admin API
  3. Re-register the account or use a different recovery path if the identity truly does not exist
  4. For integrations, check GET /admin/identities?credentials_identifier=... before programmatically triggering sends

Example fix

// before
POST /self-service/recovery  {"email": "typo@exmaple.com"}
// after
POST /self-service/recovery  {"email": "user@example.com"}  // address must match a known identity
// UI: render generic success regardless, to prevent enumeration
Defensive patterns

Strategy: try-catch

Validate before calling

// pre-check address exists (admin/integration use only)
identities, err := adminClient.ListIdentities(ctx,
  admin.IdentityListWithCredentialsIdentifier(addr))
if err != nil || len(identities) == 0 { /* unknown address */ }

Try / catch

if herodot.ErrorStatusReason(err) == http.StatusNotFound || strings.Contains(err.Error(), "unknown address") {
  // show generic message; do not reveal account existence
}

Prevention

When it happens

Trigger: Submitting a recovery/verification form (link or code strategy) with an email/address that matches no identity; recoveryV2HandleStateConfirmingAddress or recoveryHandleFormSubmission resolving no identity for the address; code sender failing its identity lookup (code_sender.go:260).

Common situations: Users mistyping their email on the recovery page; requesting recovery for an account that was deleted or never registered; tests/integrations probing with fabricated addresses.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


AI-assisted analysis of ory/kratos@b86338da04 (2026-09-07). Data as JSON: /api/errors/aa62f02035c24160. Report an issue: GitHub.

Appendix: source

Thrown at selfservice/strategy/link/sender.go:53

		logrusx.Provider
		config.Provider

		VerificationTokenPersistenceProvider
		RecoveryTokenPersistenceProvider

		hydra.Provider
		httpx.ClientProvider
	}
	SenderProvider interface {
		LinkSender() *Sender
	}

	Sender struct {
		r senderDependencies
	}
)

var ErrUnknownAddress = errors.New("verification requested for unknown address")

func NewSender(r senderDependencies) *Sender {
	return &Sender{r: r}
}

// SendRecoveryLink sends a recovery link to the specified address
//
// If the address does not exist in the store and dispatching invalid emails is enabled (CourierEnableInvalidDispatch is
// true), an email is still being sent to prevent account enumeration attacks. In that case, this function returns the
// ErrUnknownAddress error.
func (s *Sender) SendRecoveryLink(ctx context.Context, f *recovery.Flow, via, to string) error {
	s.r.Logger().
		WithField("via", via).
		WithSensitiveField("address", to).
		Debug("Preparing recovery link.")

	address, err := s.r.IdentityPool().FindRecoveryAddressByValue(ctx, via, to)
	if errors.Is(err, sqlcon.ErrNoRows()) {

View on GitHub (pinned to b86338da04)