apereo/cas · error

Unexpected multiple people returned from person attribute…

Error message

Unexpected multiple people returned from person attribute DAO: [{}] : [{}]

What it means

BasePersonAttributeDao.getSinglePerson uses Spring's DataAccessUtils.singleResult to enforce a single match; when more than one PersonAttributes is returned it catches IncorrectResultSizeDataAccessException, logs this warning with the exception details, then rethrows. The lookup ultimately fails because the query was expected to identify exactly one person.

Solutions

  1. Make the lookup attribute unique (add UNIQUE constraint, tighten the query filter)
  2. Fix duplicate records in the attribute source so only one person matches
  3. Query by a guaranteed-unique identifier (uid/principal id) instead of email or other repeatable attributes

Example fix

// before: SELECT * FROM users WHERE email = ? (duplicates possible)
// after: SELECT * FROM users WHERE uid = ? -- plus UNIQUE index on uid
Defensive patterns

Strategy: try-catch

Validate before calling

if (people != null && people.size() > 1) { /* deduplicate or refine query before calling getSinglePerson */ }

Type guard

boolean hasSingleMatch(Set<PersonAttributes> people) { return people != null && people.size() == 1; }

Try / catch

try { person = dao.getSinglePerson(people); } catch (IncorrectResultSizeDataAccessException e) { log.warn("ambiguous person lookup", e); person = null; }

Prevention

When it happens

Trigger: A person attribute DAO query (e.g., by uid/email) returns multiple rows/persons and getSinglePerson is called on the result set.

Common situations: Non-unique attribute values used as lookup keys (duplicate email addresses); missing UNIQUE constraint on the user table; overly broad LDAP/SQL filter matching several entries.

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/761fe36720260ab5. Report an issue: GitHub.

Appendix: source

Thrown at core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/attribute/BasePersonAttributeDao.java:58

    @Getter
    @Setter
    private Map<String, Object> tags = new LinkedCaseInsensitiveMap<>();

    @Override
    public int compareTo(final PersonAttributeDao o) {
        return Integer.compare(this.order, o.getOrder());
    }

    public void setId(final String... id) {
        this.id = id;
    }

    protected @Nullable PersonAttributes getSinglePerson(final @Nullable Set<PersonAttributes> people) {
        try {
            return DataAccessUtils.singleResult(people);
        } catch (final IncorrectResultSizeDataAccessException e) {
            LOGGER.warn("Unexpected multiple people returned from person attribute DAO: [{}] : [{}]", e.getClass().getName(), e.getMessage());
            if (people != null) {
                people.forEach(p -> LOGGER.debug("Person: [{}]", p));
            }
            throw e;
        }
    }

    protected Map<String, List<Object>> toMultivaluedMap(final Map<String, Object> seed) {
        val multiSeed = new LinkedCaseInsensitiveMap<List<Object>>(seed.size());
        for (val seedEntry : seed.entrySet()) {
            val seedName = seedEntry.getKey();
            val seedValue = seedEntry.getValue();
            if (seedValue instanceof final List list) {
                multiSeed.put(seedName, list);
            } else if (seedValue != null) {
                multiSeed.put(seedName, List.of(seedValue));
            }
        }

View on GitHub (pinned to e7288fc434)