{"record":{"id":"074704859f9047f6","repo":"apereo/cas","slug":"unable-to-locate-in-the-message-header","errorCode":null,"errorMessage":"Unable to locate [{}] in the message header","messagePattern":"Unable to locate \\[(.+?)\\] in the message header","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"support/cas-server-support-qr-authentication/src/main/java/org/apereo/cas/qr/web/QRAuthenticationChannelController.java","lineNumber":52,"sourceCode":"        .defaultTypingEnabled(false).build().toObjectMapper();\n\n    private final MessageSendingOperations<String> messageTemplate;\n\n    private final QRAuthenticationTokenValidatorService tokenValidatorService;\n\n    /**\n     * Verify.\n     *\n     * @param message the message\n     * @return true/false\n     */\n    @MessageMapping(\"/accept\")\n    public boolean verify(final Message<String> message) {\n        val payload = message.getPayload();\n        LOGGER.trace(\"Received payload [{}]\", payload);\n        val nativeHeaders = Objects.requireNonNull(message.getHeaders().get(\"nativeHeaders\", LinkedMultiValueMap.class));\n        if (!nativeHeaders.containsKey(QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID)) {\n            LOGGER.warn(\"Unable to locate [{}] in the message header\", QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID);\n            return false;\n        }\n        if (!nativeHeaders.containsKey(QRAuthenticationConstants.QR_AUTHENTICATION_DEVICE_ID)) {\n            LOGGER.warn(\"Unable to locate [{}] in the message header\", QRAuthenticationConstants.QR_AUTHENTICATION_DEVICE_ID);\n            return false;\n        }\n\n        val channelId = Objects.requireNonNull(nativeHeaders.get(QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID)).getFirst();\n        val endpoint = String.format(\"%s/%s/verify\", QRAuthenticationConstants.QR_SIMPLE_BROKER_DESTINATION_PREFIX, channelId);\n        try {\n            LOGGER.debug(\"Current channel id is [{}]\", channelId);\n            val resultMap = MAPPER.readValue(payload, new TypeReference<Map<String, String>>() {\n            });\n            val token = resultMap.get(TokenConstants.PARAMETER_NAME_TOKEN);\n\n            val deviceId = Objects.requireNonNull(nativeHeaders.get(QRAuthenticationConstants.QR_AUTHENTICATION_DEVICE_ID)).getFirst().toString();\n            val validationRequest = QRAuthenticationTokenValidationRequest.builder()\n                .deviceId(deviceId)","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/apereo/cas/blob/e7288fc434b4f4505b8452e1a57e8fb3111bb863/support/cas-server-support-qr-authentication/src/main/java/org/apereo/cas/qr/web/QRAuthenticationChannelController.java#L34-L70","documentation":"The QR WebSocket channel controller's verify() (@MessageMapping /accept) requires STOMP native headers to carry the QR channel id. When the incoming STOMP message lacks that header, it logs this warning and returns false instead of proceeding, preventing the QR login from being accepted.","triggerScenarios":"A STOMP client sends a message to /qr/accept without a native header named by QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID; the nativeHeaders map exists but does not contain the key.","commonSituations":"Custom WebSocket/STOMP clients that forget to set STOMP custom headers; header names mismatched in case or spelling; middleware/proxy stripping STOMP user headers; client library versions that send custom headers differently.","solutions":["Set the QR channel id as a STOMP native header on the /accept message, matching QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID exactly.","Verify the client library sends custom headers as STOMP native headers (they appear under 'nativeHeaders' server-side), e.g. stompClient.send('/qr/accept', {'qrChannelId': id}, body).","Check header name spelling/case against the constant value in QRAuthenticationConstants.","Confirm no intermediary (gateway/sockjs config) is dropping custom STOMP headers."],"exampleFix":"// before\nstompClient.send('/qr/accept', {}, payload);\n// after\nstompClient.send('/qr/accept', { 'qrChannelId': channelId, 'qrDeviceId': deviceId }, payload);","handlingStrategy":"validation","validationCode":"const headers = stompMessage.headers || {};\nif (!headers['qrChannelId']) {\n  return Promise.reject(new Error('qrChannelId native header is required'));\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize QR header names in a shared constants module used by client and server","Log nativeHeaders at trace level during client development","Verify headers survive sockjs/proxy paths"],"tags":["websocket","stomp","qr-authentication","missing-header"],"backgroundTag":"missing-required-argument","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"}