apereo/cas · warning
Unable to locate [ ] in the message header
Error message
Unable to locate [{}] in the message header What it means
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.
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.
Example fix
// before
stompClient.send('/qr/accept', {}, payload);
// after
stompClient.send('/qr/accept', { 'qrChannelId': channelId, 'qrDeviceId': deviceId }, payload); Defensive patterns
Strategy: validation
Validate before calling
const headers = stompMessage.headers || {};
if (!headers['qrChannelId']) {
return Promise.reject(new Error('qrChannelId native header is required'));
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- Unable to verify QR code
- Token has expired
- Token does not belong to the assigned principal
- Token has an invalid issuer that does not match
- Request is assigned an invalid device identifier
AI-assisted analysis of apereo/cas@e7288fc434 (2026-09-08).
Data as JSON: /api/errors/074704859f9047f6.
Report an issue: GitHub.
Appendix: source
Thrown at support/cas-server-support-qr-authentication/src/main/java/org/apereo/cas/qr/web/QRAuthenticationChannelController.java:52
.defaultTypingEnabled(false).build().toObjectMapper();
private final MessageSendingOperations<String> messageTemplate;
private final QRAuthenticationTokenValidatorService tokenValidatorService;
/**
* Verify.
*
* @param message the message
* @return true/false
*/
@MessageMapping("/accept")
public boolean verify(final Message<String> message) {
val payload = message.getPayload();
LOGGER.trace("Received payload [{}]", payload);
val nativeHeaders = Objects.requireNonNull(message.getHeaders().get("nativeHeaders", LinkedMultiValueMap.class));
if (!nativeHeaders.containsKey(QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID)) {
LOGGER.warn("Unable to locate [{}] in the message header", QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID);
return false;
}
if (!nativeHeaders.containsKey(QRAuthenticationConstants.QR_AUTHENTICATION_DEVICE_ID)) {
LOGGER.warn("Unable to locate [{}] in the message header", QRAuthenticationConstants.QR_AUTHENTICATION_DEVICE_ID);
return false;
}
val channelId = Objects.requireNonNull(nativeHeaders.get(QRAuthenticationConstants.QR_AUTHENTICATION_CHANNEL_ID)).getFirst();
val endpoint = String.format("%s/%s/verify", QRAuthenticationConstants.QR_SIMPLE_BROKER_DESTINATION_PREFIX, channelId);
try {
LOGGER.debug("Current channel id is [{}]", channelId);
val resultMap = MAPPER.readValue(payload, new TypeReference<Map<String, String>>() {
});
val token = resultMap.get(TokenConstants.PARAMETER_NAME_TOKEN);
val deviceId = Objects.requireNonNull(nativeHeaders.get(QRAuthenticationConstants.QR_AUTHENTICATION_DEVICE_ID)).getFirst().toString();
val validationRequest = QRAuthenticationTokenValidationRequest.builder()
.deviceId(deviceId)View on GitHub (pinned to e7288fc434)