{"record":{"id":"fe64eb8cc089c2cc","repo":"YunaiV/yudao-cloud","slug":"error","errorCode":null,"errorMessage":"未知的数据类型：{}","messagePattern":"未知的数据类型：(.+?)","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java","lineNumber":149,"sourceCode":"\n    private Long parseTenantId(Message<?> message) {\n        Object tenantId = message.getHeaders().get(HEADER_TENANT_ID);\n        if (tenantId == null) {\n            return null;\n        }\n        if (tenantId instanceof Long) {\n            return (Long) tenantId;\n        }\n        if (tenantId instanceof Number) {\n            return ((Number) tenantId).longValue();\n        }\n        if (tenantId instanceof String) {\n            return Long.parseLong((String) tenantId);\n        }\n        if (tenantId instanceof byte[]) {\n            return Long.parseLong(new String((byte[]) tenantId));\n        }\n        throw new IllegalArgumentException(\"未知的数据类型：\" + tenantId);\n    }\n\n    /**\n     * Get the method argument values for the current message, checking the provided\n     * argument values and falling back to the configured argument resolvers.\n     * <p>The resulting array will be passed into {@link #doInvoke}.\n     * @since 5.1.2\n     */\n    protected Object[] getMethodArgumentValues(Message<?> message, Object... providedArgs) throws Exception {\n        MethodParameter[] parameters = getMethodParameters();\n        if (ObjectUtils.isEmpty(parameters)) {\n            return EMPTY_ARGS;\n        }\n\n        Object[] args = new Object[parameters.length];\n        for (int i = 0; i < parameters.length; i++) {\n            MethodParameter parameter = parameters[i];\n            parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/YunaiV/yudao-cloud/blob/477be9dd49ab7223a972a6abdff0684d6423dec3/yudao-framework/yudao-spring-boot-starter-biz-tenant/src/main/java/org/springframework/messaging/handler/invocation/InvocableHandlerMethod.java#L131-L167","documentation":"A patched Spring InvocableHandlerMethod converts an incoming message header (the tenant id) to Long. It handles Long, Number, numeric String, and byte[] of digits; any other runtime type (Map, JsonObject, non-numeric String, null-wrapped weirdly) triggers IllegalArgumentException with the value printed.","triggerScenarios":"A WebSocket/RabbitMQ/Redis message carries the tenant header as a non-numeric payload — e.g. JSON object {\"tenantId\": \"tenant-a\"}, a UUID string, or the tenant propagation header set from user input without validation; Long.parseLong('1abc') inside the String/byte[] branch throws NumberFormatException in the same conversion helper.","commonSituations":"Frontend sends tenant-id header with whitespace or quotes ('\"1\"'); a gateway/proxy rewrites the header to a non-numeric tenant code; payload schemas that serialize numbers as JSON strings with units; version drift where a client starts sending tenant 'name' instead of id.","solutions":["Send the tenant id strictly as a base-10 numeric value (string or number), no quotes/whitespace.","Validate the header at the edge (gateway filter or controller advice) before it reaches the messaging layer.","If tenants must be addressed by code, resolve code->id at the boundary and only propagate the numeric id.","Check the printed value in the message to identify which client/message is malformed."],"exampleFix":"// client before\nheaders.put(\"tenant-id\", \"\\\"1\\\"\"); // quoted -> parse fails\n\n// client after\nheaders.put(\"tenant-id\", \"1\");","handlingStrategy":"validation","validationCode":"Object raw = message.getHeaders().get(\"tenant-id\");\nif (raw instanceof String s && !s.matches(\"\\\\d+\")) {\n    throw new IllegalArgumentException(\"tenant-id must be numeric, got: \" + s);\n}","typeGuard":"static boolean isConvertibleTenantId(Object v) {\n    return v instanceof Long || v instanceof Number || v instanceof byte[]\n        || (v instanceof String s && s.matches(\"\\\\d+\"));\n}","tryCatchPattern":"try {\n    Long tenantId = convertTenant(message.getHeaders().get(\"tenant-id\"));\n} catch (IllegalArgumentException | NumberFormatException e) {\n    rejectMessageWithReason(\"invalid tenant-id header: \" + e.getMessage());\n}","preventionTips":["Validate the tenant-id header format at gateway/edge before messages reach handlers","Standardize tenant propagation as a plain base-10 numeric string in all clients"],"tags":["yudao","multi-tenant","messaging","type-conversion","websocket"],"backgroundTag":null,"analyzedSha":"477be9dd49ab7223a972a6abdff0684d6423dec3","analyzedAt":"2026-08-14T13:35:31.121Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}