apereo/cas · warning

No recipient is provided with a valid email/phone

Error message

No recipient is provided with a valid email/phone

What it means

SendPasswordResetInstructionsAction (webflow action) looks up the request's email(s) and phone for the password-reset query; when neither yields a recipient it logs this warn and returns the invalid-contact event, sending the user back to the prompt screen instead of generating a reset link.

Solutions

  1. Ensure the user record has a valid mail or sms attribute matching cas.authn.pm.reset.mail/sms.attributeName
  2. Enable debug logging on org.apereo.cas.pm to see which lookup (email vs phone) failed and why
  3. Validate the username submitted on the form corresponds to an existing directory entry
  4. Check the underlying service is not the no-op PM service (see no-op warn)

Example fix

// before — webflow returns 'invalidContact' because mail attribute is empty
// after — set in directory: mail: user@example.com
// action then proceeds and stores the PasswordManagementQuery in flow scope
Defensive patterns

Strategy: validation

Validate before calling

// before submitting the reset form, verify a contact exists
var query = PasswordManagementQuery.builder().username(username).build();
boolean reachable = !pmService.findEmails(query).isEmpty() || StringUtils.isNotBlank(pmService.findPhone(query));
if (!reachable) { showInvalidContactMessage(); }

Prevention

When it happens

Trigger: doExecuteInternal runs with locatePasswordResetRequestEmail returning an empty collection and locatePasswordResetRequestPhone returning nothing — the PM service found no valid contact for the username entered on the reset form.

Common situations: Typo'd username on the reset form mapping to an entry without contact attributes; mail attribute fails email validation; LDAP bind/search misconfigured so lookups return nothing; testing with users that have no mail/mobile populated.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08). Data as JSON: /api/errors/32e2a98a81e75b35. Report an issue: GitHub.

Appendix: source

Thrown at support/cas-server-support-pm-webflow/src/main/java/org/apereo/cas/pm/web/flow/actions/SendPasswordResetInstructionsAction.java:126

        actionResolverName = AuditActionResolvers.REQUEST_CHANGE_PASSWORD_ACTION_RESOLVER,
        resourceResolverName = AuditResourceResolvers.REQUEST_CHANGE_PASSWORD_RESOURCE_RESOLVER)
    @Override
    protected @Nullable Event doExecuteInternal(final RequestContext requestContext) throws Throwable {
        communicationsManager.validate();
        if (!communicationsManager.isMailSenderDefined() && !communicationsManager.isSmsSenderDefined()) {
            return getErrorEvent("contact.failed", "Unable to send email as no mail sender is defined", requestContext);
        }

        val query = buildPasswordManagementQuery(requestContext);
        if (StringUtils.isBlank(query.getUsername())) {
            return getErrorEvent("username.required", "No username is provided", requestContext);
        }

        val emails = locatePasswordResetRequestEmail(requestContext, query);
        val phones = locatePasswordResetRequestPhone(requestContext, query);

        if (emails.isEmpty() && phones.isEmpty()) {
            LOGGER.warn("No recipient is provided with a valid email/phone");
            return getInvalidContactEvent(requestContext);
        }
        WebUtils.putPasswordManagementQuery(requestContext, query);
        if (doesPasswordResetRequireMultifactorAuthentication(requestContext)
            && !hasPrincipalRegisteredMultifactorAuthenticationDevice(requestContext)) {
            LOGGER.warn("No registered devices for multifactor authentication could be found for [{}]", query.getUsername());
            WebUtils.addErrorMessageToContext(requestContext, "screen.mfaDenied.message");
            return eventFactory.event(this, CasWebflowConstants.TRANSITION_ID_DENY);
        }
        val service = WebUtils.getService(requestContext);
        val url = buildPasswordResetUrl(query.getUsername(), service);
        if (url != null) {
            val sendEmail = sendPasswordResetEmailToAccount(query.getUsername(), emails, url, requestContext);
            val sendSms = sendPasswordResetSmsToAccount(requestContext, phones, url);
            if (sendEmail.isSuccess() || sendSms) {
                return success(url);
            }
        } else {

View on GitHub (pinned to e7288fc434)