{"record":{"id":"b32c9339bc06d2f9","repo":"spring-projects/spring-security","slug":"duplicate-key-registrationid","errorCode":null,"errorMessage":"Duplicate key ${registrationId}","messagePattern":"Duplicate key (.+?)","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepository.java","lineNumber":88,"sourceCode":"\t\treturn Mono.justOrEmpty(this.clientIdToClientRegistration.get(registrationId));\n\t}\n\n\t/**\n\t * Returns an {@code Iterator} of {@link ClientRegistration}.\n\t * @return an {@code Iterator<ClientRegistration>}\n\t */\n\t@Override\n\tpublic Iterator<ClientRegistration> iterator() {\n\t\treturn this.clientIdToClientRegistration.values().iterator();\n\t}\n\n\tprivate static Map<String, ClientRegistration> toUnmodifiableConcurrentMap(List<ClientRegistration> registrations) {\n\t\tAssert.notEmpty(registrations, \"registrations cannot be null or empty\");\n\t\tConcurrentHashMap<String, ClientRegistration> result = new ConcurrentHashMap<>();\n\t\tfor (ClientRegistration registration : registrations) {\n\t\t\tAssert.notNull(registration, \"no registration can be null\");\n\t\t\tif (result.containsKey(registration.getRegistrationId())) {\n\t\t\t\tthrow new IllegalStateException(String.format(\"Duplicate key %s\", registration.getRegistrationId()));\n\t\t\t}\n\t\t\tresult.put(registration.getRegistrationId(), registration);\n\t\t}\n\t\treturn Collections.unmodifiableMap(result);\n\t}\n\n}\n","sourceCodeStart":70,"sourceCodeEnd":96,"githubUrl":"https://github.com/spring-projects/spring-security/blob/96852e8860138a482cb13d1479573f24ff6443c6/oauth2/oauth2-client/src/main/java/org/springframework/security/oauth2/client/registration/InMemoryReactiveClientRegistrationRepository.java#L70-L96","documentation":"InMemoryReactiveClientRegistrationRepository stores ClientRegistrations in an unmodifiable map keyed by registrationId. During construction it detects two registrations with the same registrationId and throws this IllegalStateException, because a duplicate key would silently overwrite a registration and break request matching.","triggerScenarios":"new InMemoryReactiveClientRegistrationRepository(List<ClientRegistration>) where two registrations in the list share the same getRegistrationId() (checked in toUnmodifiableConcurrentMap).","commonSituations":"Loading registrations from application.yml via ClientRegistrationRepository beans and also declaring them manually; iterating over multiple issuer configs that all use the same registrationId placeholder; copying a registration and only changing clientId, forgetting the registrationId.","solutions":["Make every registrationId unique across all registrations passed to the constructor.","If a bean-based config auto-generates registrations, exclude the duplicates instead of adding manual copies.","Centralize registration creation (e.g. a @Bean returning the repository) so ids can't collide between config files and code.","On failure, log each registration's getRegistrationId() before constructing to spot the duplicate quickly."],"exampleFix":"// before\nnew InMemoryReactiveClientRegistrationRepository(List.of(\n  ClientRegistration.withRegistrationId(\"idp\")...build(),\n  ClientRegistration.withRegistrationId(\"idp\")...build())) // duplicate\n// after\nnew InMemoryReactiveClientRegistrationRepository(List.of(\n  ClientRegistration.withRegistrationId(\"idp\")...build(),\n  ClientRegistration.withRegistrationId(\"idp-2\")...build()))","handlingStrategy":"validation","validationCode":"Set<String> seen = new HashSet<>();\nfor (ClientRegistration r : registrations) {\n    if (!seen.add(r.getRegistrationId())) throw new IllegalStateException(\"duplicate registrationId \" + r.getRegistrationId());\n}","typeGuard":null,"tryCatchPattern":"try { new InMemoryReactiveClientRegistrationRepository(registrations); } catch (IllegalStateException e) { if (e.getMessage().startsWith(\"Duplicate key\")) { /* dedupe list and retry */ } throw e; }","preventionTips":["Generate registrationIds deterministically from tenant/issuer names","Dedupe registrations by id before constructing the repository","Add a unit test asserting unique registrationIds in config"],"tags":["oauth2","configuration","duplicate-key"],"backgroundTag":"conflicting-config-options","analyzedSha":"96852e8860138a482cb13d1479573f24ff6443c6","analyzedAt":"2026-09-10T23:25:23.477Z","contentChangedAt":"2026-09-10T23:25:23.477Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}