{"record":{"id":"761fe36720260ab5","repo":"apereo/cas","slug":"unexpected-multiple-people-returned-from-person-at","errorCode":null,"errorMessage":"Unexpected multiple people returned from person attribute DAO: [{}] : [{}]","messagePattern":"Unexpected multiple people returned from person attribute DAO: \\[(.+?)\\] : \\[(.+?)\\]","errorType":"console","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/attribute/BasePersonAttributeDao.java","lineNumber":58,"sourceCode":"\n    @Getter\n    @Setter\n    private Map<String, Object> tags = new LinkedCaseInsensitiveMap<>();\n\n    @Override\n    public int compareTo(final PersonAttributeDao o) {\n        return Integer.compare(this.order, o.getOrder());\n    }\n\n    public void setId(final String... id) {\n        this.id = id;\n    }\n\n    protected @Nullable PersonAttributes getSinglePerson(final @Nullable Set<PersonAttributes> people) {\n        try {\n            return DataAccessUtils.singleResult(people);\n        } catch (final IncorrectResultSizeDataAccessException e) {\n            LOGGER.warn(\"Unexpected multiple people returned from person attribute DAO: [{}] : [{}]\", e.getClass().getName(), e.getMessage());\n            if (people != null) {\n                people.forEach(p -> LOGGER.debug(\"Person: [{}]\", p));\n            }\n            throw e;\n        }\n    }\n\n    protected Map<String, List<Object>> toMultivaluedMap(final Map<String, Object> seed) {\n        val multiSeed = new LinkedCaseInsensitiveMap<List<Object>>(seed.size());\n        for (val seedEntry : seed.entrySet()) {\n            val seedName = seedEntry.getKey();\n            val seedValue = seedEntry.getValue();\n            if (seedValue instanceof final List list) {\n                multiSeed.put(seedName, list);\n            } else if (seedValue != null) {\n                multiSeed.put(seedName, List.of(seedValue));\n            }\n        }","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/core/cas-server-core-authentication-api/src/main/java/org/apereo/cas/authentication/attribute/BasePersonAttributeDao.java#L40-L76","documentation":"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.","triggerScenarios":"A person attribute DAO query (e.g., by uid/email) returns multiple rows/persons and getSinglePerson is called on the result set.","commonSituations":"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.","solutions":["Make the lookup attribute unique (add UNIQUE constraint, tighten the query filter)","Fix duplicate records in the attribute source so only one person matches","Query by a guaranteed-unique identifier (uid/principal id) instead of email or other repeatable attributes"],"exampleFix":"// before: SELECT * FROM users WHERE email = ? (duplicates possible)\n// after: SELECT * FROM users WHERE uid = ? -- plus UNIQUE index on uid","handlingStrategy":"try-catch","validationCode":"if (people != null && people.size() > 1) { /* deduplicate or refine query before calling getSinglePerson */ }","typeGuard":"boolean hasSingleMatch(Set<PersonAttributes> people) { return people != null && people.size() == 1; }","tryCatchPattern":"try { person = dao.getSinglePerson(people); } catch (IncorrectResultSizeDataAccessException e) { log.warn(\"ambiguous person lookup\", e); person = null; }","preventionTips":["Enforce uniqueness of lookup attributes in the data store","Always query by guaranteed-unique identifiers","Deduplicate result sets before single-result extraction"],"tags":["person-attribute-dao","duplicate-records","unique-constraint","attribute-resolution"],"backgroundTag":"empty-result-set","analyzedSha":"e7288fc434b4f4505b8452e1a57e8fb3111bb863","analyzedAt":"2026-09-08T15:39:16.015Z","contentChangedAt":"2026-09-08T15:39:16.015Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}