/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.kafka.common.protocol; import org.apache.kafka.common.errors.ApiException; import org.apache.kafka.common.errors.BrokerAuthorizationException; import org.apache.kafka.common.errors.BrokerNotAvailableException; import org.apache.kafka.common.errors.ClusterAuthorizationException; import org.apache.kafka.common.errors.ConcurrentTransactionsException; import org.apache.kafka.common.errors.ControllerMovedException; import org.apache.kafka.common.errors.CoordinatorLoadInProgressException; import org.apache.kafka.common.errors.CoordinatorNotAvailableException; import org.apache.kafka.common.errors.CorruptRecordException; import org.apache.kafka.common.errors.DuplicateSequenceNumberException; import org.apache.kafka.common.errors.GroupAuthorizationException; import org.apache.kafka.common.errors.IllegalGenerationException; import org.apache.kafka.common.errors.IllegalSaslStateException; import org.apache.kafka.common.errors.InconsistentGroupProtocolException; import org.apache.kafka.common.errors.InvalidCommitOffsetSizeException; import org.apache.kafka.common.errors.InvalidConfigurationException; import org.apache.kafka.common.errors.InvalidFetchSizeException; import org.apache.kafka.common.errors.InvalidGroupIdException; import org.apache.kafka.common.errors.InvalidPartitionsException; import org.apache.kafka.common.errors.InvalidPidMappingException; import org.apache.kafka.common.errors.InvalidReplicaAssignmentException; import org.apache.kafka.common.errors.InvalidReplicationFactorException; import org.apache.kafka.common.errors.InvalidRequestException; import org.apache.kafka.common.errors.InvalidRequiredAcksException; import org.apache.kafka.common.errors.InvalidSessionTimeoutException; import org.apache.kafka.common.errors.InvalidTimestampException; import org.apache.kafka.common.errors.InvalidTopicException; import org.apache.kafka.common.errors.InvalidTxnStateException; import org.apache.kafka.common.errors.InvalidTxnTimeoutException; import org.apache.kafka.common.errors.LeaderNotAvailableException; import org.apache.kafka.common.errors.NetworkException; import org.apache.kafka.common.errors.NotControllerException; import org.apache.kafka.common.errors.NotCoordinatorException; import org.apache.kafka.common.errors.NotEnoughReplicasAfterAppendException; import org.apache.kafka.common.errors.NotEnoughReplicasException; import org.apache.kafka.common.errors.NotLeaderForPartitionException; import org.apache.kafka.common.errors.OffsetMetadataTooLarge; import org.apache.kafka.common.errors.OffsetOutOfRangeException; import org.apache.kafka.common.errors.OutOfOrderSequenceException; import org.apache.kafka.common.errors.PolicyViolationException; import org.apache.kafka.common.errors.ProducerFencedException; import org.apache.kafka.common.errors.ProducerIdAuthorizationException; import org.apache.kafka.common.errors.RebalanceInProgressException; import org.apache.kafka.common.errors.RecordBatchTooLargeException; import org.apache.kafka.common.errors.RecordTooLargeException; import org.apache.kafka.common.errors.ReplicaNotAvailableException; import org.apache.kafka.common.errors.RetriableException; import org.apache.kafka.common.errors.SecurityDisabledException; import org.apache.kafka.common.errors.TimeoutException; import org.apache.kafka.common.errors.TopicAuthorizationException; import org.apache.kafka.common.errors.TopicExistsException; import org.apache.kafka.common.errors.TransactionalIdAuthorizationException; import org.apache.kafka.common.errors.TransactionCoordinatorFencedException; import org.apache.kafka.common.errors.UnknownMemberIdException; import org.apache.kafka.common.errors.UnknownServerException; import org.apache.kafka.common.errors.UnknownTopicOrPartitionException; import org.apache.kafka.common.errors.UnsupportedForMessageFormatException; import org.apache.kafka.common.errors.UnsupportedSaslMechanismException; import org.apache.kafka.common.errors.UnsupportedVersionException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; /** * This class contains all the client-server errors--those errors that must be sent from the server to the client. These * are thus part of the protocol. The names can be changed but the error code cannot. * * Do not add exceptions that occur only on the client or only on the server here. */ public enum Errors { UNKNOWN(-1, "The server experienced an unexpected error when processing the request", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new UnknownServerException(message); } }), NONE(0, null, new ApiExceptionBuilder() { @Override public ApiException build(String message) { return null; } }), OFFSET_OUT_OF_RANGE(1, "The requested offset is not within the range of offsets maintained by the server.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new OffsetOutOfRangeException(message); } }), CORRUPT_MESSAGE(2, "This message has failed its CRC checksum, exceeds the valid size, or is otherwise corrupt.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new CorruptRecordException(message); } }), UNKNOWN_TOPIC_OR_PARTITION(3, "This server does not host this topic-partition.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new UnknownTopicOrPartitionException(message); } }), INVALID_FETCH_SIZE(4, "The requested fetch size is invalid.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidFetchSizeException(message); } }), LEADER_NOT_AVAILABLE(5, "There is no leader for this topic-partition as we are in the middle of a leadership election.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new LeaderNotAvailableException(message); } }), NOT_LEADER_FOR_PARTITION(6, "This server is not the leader for that topic-partition.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new NotLeaderForPartitionException(message); } }), REQUEST_TIMED_OUT(7, "The request timed out.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new TimeoutException(message); } }), BROKER_NOT_AVAILABLE(8, "The broker is not available.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new BrokerNotAvailableException(message); } }), REPLICA_NOT_AVAILABLE(9, "The replica is not available for the requested topic-partition", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new ReplicaNotAvailableException(message); } }), MESSAGE_TOO_LARGE(10, "The request included a message larger than the max message size the server will accept.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new RecordTooLargeException(message); } }), STALE_CONTROLLER_EPOCH(11, "The controller moved to another broker.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new ControllerMovedException(message); } }), OFFSET_METADATA_TOO_LARGE(12, "The metadata field of the offset request was too large.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new OffsetMetadataTooLarge(message); } }), NETWORK_EXCEPTION(13, "The server disconnected before a response was received.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new NetworkException(message); } }), COORDINATOR_LOAD_IN_PROGRESS(14, "The coordinator is loading and hence can't process requests.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new CoordinatorLoadInProgressException(message); } }), COORDINATOR_NOT_AVAILABLE(15, "The coordinator is not available.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new CoordinatorNotAvailableException(message); } }), NOT_COORDINATOR(16, "This is not the correct coordinator.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new NotCoordinatorException(message); } }), INVALID_TOPIC_EXCEPTION(17, "The request attempted to perform an operation on an invalid topic.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidTopicException(message); } }), RECORD_LIST_TOO_LARGE(18, "The request included message batch larger than the configured segment size on the server.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new RecordBatchTooLargeException(message); } }), NOT_ENOUGH_REPLICAS(19, "Messages are rejected since there are fewer in-sync replicas than required.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new NotEnoughReplicasException(message); } }), NOT_ENOUGH_REPLICAS_AFTER_APPEND(20, "Messages are written to the log, but to fewer in-sync replicas than required.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new NotEnoughReplicasAfterAppendException(message); } }), INVALID_REQUIRED_ACKS(21, "Produce request specified an invalid value for required acks.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidRequiredAcksException(message); } }), ILLEGAL_GENERATION(22, "Specified group generation id is not valid.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new IllegalGenerationException(message); } }), INCONSISTENT_GROUP_PROTOCOL(23, "The group member's supported protocols are incompatible with those of existing members.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InconsistentGroupProtocolException(message); } }), INVALID_GROUP_ID(24, "The configured groupId is invalid", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidGroupIdException(message); } }), UNKNOWN_MEMBER_ID(25, "The coordinator is not aware of this member.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new UnknownMemberIdException(message); } }), INVALID_SESSION_TIMEOUT(26, "The session timeout is not within the range allowed by the broker " + "(as configured by group.min.session.timeout.ms and group.max.session.timeout.ms).", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidSessionTimeoutException(message); } }), REBALANCE_IN_PROGRESS(27, "The group is rebalancing, so a rejoin is needed.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new RebalanceInProgressException(message); } }), INVALID_COMMIT_OFFSET_SIZE(28, "The committing offset data size is not valid", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidCommitOffsetSizeException(message); } }), TOPIC_AUTHORIZATION_FAILED(29, "Topic authorization failed.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new TopicAuthorizationException(message); } }), GROUP_AUTHORIZATION_FAILED(30, "Group authorization failed.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new GroupAuthorizationException(message); } }), CLUSTER_AUTHORIZATION_FAILED(31, "Cluster authorization failed.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new ClusterAuthorizationException(message); } }), INVALID_TIMESTAMP(32, "The timestamp of the message is out of acceptable range.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidTimestampException(message); } }), UNSUPPORTED_SASL_MECHANISM(33, "The broker does not support the requested SASL mechanism.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new UnsupportedSaslMechanismException(message); } }), ILLEGAL_SASL_STATE(34, "Request is not valid given the current SASL state.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new IllegalSaslStateException(message); } }), UNSUPPORTED_VERSION(35, "The version of API is not supported.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new UnsupportedVersionException(message); } }), TOPIC_ALREADY_EXISTS(36, "Topic with this name already exists.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new TopicExistsException(message); } }), INVALID_PARTITIONS(37, "Number of partitions is invalid.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidPartitionsException(message); } }), INVALID_REPLICATION_FACTOR(38, "Replication-factor is invalid.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidReplicationFactorException(message); } }), INVALID_REPLICA_ASSIGNMENT(39, "Replica assignment is invalid.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidReplicaAssignmentException(message); } }), INVALID_CONFIG(40, "Configuration is invalid.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidConfigurationException(message); } }), NOT_CONTROLLER(41, "This is not the correct controller for this cluster.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new NotControllerException(message); } }), INVALID_REQUEST(42, "This most likely occurs because of a request being malformed by the " + "client library or the message was sent to an incompatible broker. See the broker logs " + "for more details.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidRequestException(message); } }), UNSUPPORTED_FOR_MESSAGE_FORMAT(43, "The message format version on the broker does not support the request.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new UnsupportedForMessageFormatException(message); } }), POLICY_VIOLATION(44, "Request parameters do not satisfy the configured policy.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new PolicyViolationException(message); } }), OUT_OF_ORDER_SEQUENCE_NUMBER(45, "The broker received an out of order sequence number", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new OutOfOrderSequenceException(message); } }), DUPLICATE_SEQUENCE_NUMBER(46, "The broker received a duplicate sequence number", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new DuplicateSequenceNumberException(message); } }), INVALID_PRODUCER_EPOCH(47, "Producer attempted an operation with an old epoch", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new ProducerFencedException(message); } }), INVALID_TXN_STATE(48, "The producer attempted a transactional operation in an invalid state", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidTxnStateException(message); } }), INVALID_PRODUCER_ID_MAPPING(49, "The producer attempted to use a producer id which is not currently assigned to " + "its transactional id", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidPidMappingException(message); } }), INVALID_TRANSACTION_TIMEOUT(50, "The transaction timeout is larger than the maximum value allowed by " + "the broker (as configured by max.transaction.timeout.ms).", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new InvalidTxnTimeoutException(message); } }), CONCURRENT_TRANSACTIONS(51, "The producer attempted to update a transaction " + "while another concurrent operation on the same transaction was ongoing", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new ConcurrentTransactionsException(message); } }), TRANSACTION_COORDINATOR_FENCED(52, "Indicates that the transaction coordinator sending a WriteTxnMarker " + "is no longer the current coordinator for a given producer", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new TransactionCoordinatorFencedException(message); } }), TRANSACTIONAL_ID_AUTHORIZATION_FAILED(53, "Transactional Id authorization failed", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new TransactionalIdAuthorizationException(message); } }), PRODUCER_ID_AUTHORIZATION_FAILED(54, "Producer is not authorized to use producer Ids, " + "which is required to write idempotent data.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new ProducerIdAuthorizationException(message); } }), SECURITY_DISABLED(55, "Security features are disabled.", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new SecurityDisabledException(message); } }), BROKER_AUTHORIZATION_FAILED(56, "Broker authorization failed", new ApiExceptionBuilder() { @Override public ApiException build(String message) { return new BrokerAuthorizationException(message); } }); private interface ApiExceptionBuilder { ApiException build(String message); } private static final Logger log = LoggerFactory.getLogger(Errors.class); private static Map<Class<?>, Errors> classToError = new HashMap<>(); private static Map<Short, Errors> codeToError = new HashMap<>(); static { for (Errors error : Errors.values()) { codeToError.put(error.code(), error); if (error.exception != null) classToError.put(error.exception.getClass(), error); } } private final short code; private final ApiExceptionBuilder builder; private final ApiException exception; Errors(int code, String defaultExceptionString, ApiExceptionBuilder builder) { this.code = (short) code; this.builder = builder; this.exception = builder.build(defaultExceptionString); } /** * An instance of the exception */ public ApiException exception() { return this.exception; } /** * Create an instance of the ApiException that contains the given error message. * * @param message The message string to set. * @return The exception. */ public ApiException exception(String message) { if (message == null) { // If no error message was specified, return an exception with the default error message. return exception; } // Return an exception with the given error message. return builder.build(message); } /** * Returns the class name of the exception or null if this is {@code Errors.NONE}. */ public String exceptionName() { return exception == null ? null : exception.getClass().getName(); } /** * The error code for the exception */ public short code() { return this.code; } /** * Throw the exception corresponding to this error if there is one */ public void maybeThrow() { if (exception != null) { throw this.exception; } } /** * Get a friendly description of the error (if one is available). * @return the error message */ public String message() { if (exception != null) return exception.getMessage(); return toString(); } /** * Throw the exception if there is one */ public static Errors forCode(short code) { Errors error = codeToError.get(code); if (error != null) { return error; } else { log.warn("Unexpected error code: {}.", code); return UNKNOWN; } } /** * Return the error instance associated with this exception or any of its superclasses (or UNKNOWN if there is none). * If there are multiple matches in the class hierarchy, the first match starting from the bottom is used. */ public static Errors forException(Throwable t) { Class<?> clazz = t.getClass(); while (clazz != null) { Errors error = classToError.get(clazz); if (error != null) return error; clazz = clazz.getSuperclass(); } return UNKNOWN; } private static String toHtml() { final StringBuilder b = new StringBuilder(); b.append("<table class=\"data-table\"><tbody>\n"); b.append("<tr>"); b.append("<th>Error</th>\n"); b.append("<th>Code</th>\n"); b.append("<th>Retriable</th>\n"); b.append("<th>Description</th>\n"); b.append("</tr>\n"); for (Errors error : Errors.values()) { b.append("<tr>"); b.append("<td>"); b.append(error.name()); b.append("</td>"); b.append("<td>"); b.append(error.code()); b.append("</td>"); b.append("<td>"); b.append(error.exception() != null && error.exception() instanceof RetriableException ? "True" : "False"); b.append("</td>"); b.append("<td>"); b.append(error.exception() != null ? error.exception().getMessage() : ""); b.append("</td>"); b.append("</tr>\n"); } b.append("</table>\n"); return b.toString(); } public static void main(String[] args) { System.out.println(toHtml()); } }