github.com/rbisecke/kafka-go@v0.4.27/error.go (about)

     1  package kafka
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"io"
     7  	"syscall"
     8  )
     9  
    10  // Error represents the different error codes that may be returned by kafka.
    11  // https://kafka.apache.org/protocol#protocol_error_codes
    12  type Error int
    13  
    14  const (
    15  	Unknown                            Error = -1
    16  	OffsetOutOfRange                   Error = 1
    17  	InvalidMessage                     Error = 2
    18  	UnknownTopicOrPartition            Error = 3
    19  	InvalidMessageSize                 Error = 4
    20  	LeaderNotAvailable                 Error = 5
    21  	NotLeaderForPartition              Error = 6
    22  	RequestTimedOut                    Error = 7
    23  	BrokerNotAvailable                 Error = 8
    24  	ReplicaNotAvailable                Error = 9
    25  	MessageSizeTooLarge                Error = 10
    26  	StaleControllerEpoch               Error = 11
    27  	OffsetMetadataTooLarge             Error = 12
    28  	NetworkException                   Error = 13
    29  	GroupLoadInProgress                Error = 14
    30  	GroupCoordinatorNotAvailable       Error = 15
    31  	NotCoordinatorForGroup             Error = 16
    32  	InvalidTopic                       Error = 17
    33  	RecordListTooLarge                 Error = 18
    34  	NotEnoughReplicas                  Error = 19
    35  	NotEnoughReplicasAfterAppend       Error = 20
    36  	InvalidRequiredAcks                Error = 21
    37  	IllegalGeneration                  Error = 22
    38  	InconsistentGroupProtocol          Error = 23
    39  	InvalidGroupId                     Error = 24
    40  	UnknownMemberId                    Error = 25
    41  	InvalidSessionTimeout              Error = 26
    42  	RebalanceInProgress                Error = 27
    43  	InvalidCommitOffsetSize            Error = 28
    44  	TopicAuthorizationFailed           Error = 29
    45  	GroupAuthorizationFailed           Error = 30
    46  	ClusterAuthorizationFailed         Error = 31
    47  	InvalidTimestamp                   Error = 32
    48  	UnsupportedSASLMechanism           Error = 33
    49  	IllegalSASLState                   Error = 34
    50  	UnsupportedVersion                 Error = 35
    51  	TopicAlreadyExists                 Error = 36
    52  	InvalidPartitionNumber             Error = 37
    53  	InvalidReplicationFactor           Error = 38
    54  	InvalidReplicaAssignment           Error = 39
    55  	InvalidConfiguration               Error = 40
    56  	NotController                      Error = 41
    57  	InvalidRequest                     Error = 42
    58  	UnsupportedForMessageFormat        Error = 43
    59  	PolicyViolation                    Error = 44
    60  	OutOfOrderSequenceNumber           Error = 45
    61  	DuplicateSequenceNumber            Error = 46
    62  	InvalidProducerEpoch               Error = 47
    63  	InvalidTransactionState            Error = 48
    64  	InvalidProducerIDMapping           Error = 49
    65  	InvalidTransactionTimeout          Error = 50
    66  	ConcurrentTransactions             Error = 51
    67  	TransactionCoordinatorFenced       Error = 52
    68  	TransactionalIDAuthorizationFailed Error = 53
    69  	SecurityDisabled                   Error = 54
    70  	BrokerAuthorizationFailed          Error = 55
    71  	KafkaStorageError                  Error = 56
    72  	LogDirNotFound                     Error = 57
    73  	SASLAuthenticationFailed           Error = 58
    74  	UnknownProducerId                  Error = 59
    75  	ReassignmentInProgress             Error = 60
    76  	DelegationTokenAuthDisabled        Error = 61
    77  	DelegationTokenNotFound            Error = 62
    78  	DelegationTokenOwnerMismatch       Error = 63
    79  	DelegationTokenRequestNotAllowed   Error = 64
    80  	DelegationTokenAuthorizationFailed Error = 65
    81  	DelegationTokenExpired             Error = 66
    82  	InvalidPrincipalType               Error = 67
    83  	NonEmptyGroup                      Error = 68
    84  	GroupIdNotFound                    Error = 69
    85  	FetchSessionIDNotFound             Error = 70
    86  	InvalidFetchSessionEpoch           Error = 71
    87  	ListenerNotFound                   Error = 72
    88  	TopicDeletionDisabled              Error = 73
    89  	FencedLeaderEpoch                  Error = 74
    90  	UnknownLeaderEpoch                 Error = 75
    91  	UnsupportedCompressionType         Error = 76
    92  	StaleBrokerEpoch                   Error = 77
    93  	OffsetNotAvailable                 Error = 78
    94  	MemberIDRequired                   Error = 79
    95  	PreferredLeaderNotAvailable        Error = 80
    96  	GroupMaxSizeReached                Error = 81
    97  	FencedInstanceID                   Error = 82
    98  	EligibleLeadersNotAvailable        Error = 83
    99  	ElectionNotNeeded                  Error = 84
   100  	NoReassignmentInProgress           Error = 85
   101  	GroupSubscribedToTopic             Error = 86
   102  	InvalidRecord                      Error = 87
   103  	UnstableOffsetCommit               Error = 88
   104  )
   105  
   106  // Error satisfies the error interface.
   107  func (e Error) Error() string {
   108  	return fmt.Sprintf("[%d] %s: %s", e, e.Title(), e.Description())
   109  }
   110  
   111  // Timeout returns true if the error was due to a timeout.
   112  func (e Error) Timeout() bool {
   113  	return e == RequestTimedOut
   114  }
   115  
   116  // Temporary returns true if the operation that generated the error may succeed
   117  // if retried at a later time.
   118  // Kafka error documentation specifies these as "retriable"
   119  // https://kafka.apache.org/protocol#protocol_error_codes
   120  func (e Error) Temporary() bool {
   121  	switch e {
   122  	case InvalidMessage,
   123  		UnknownTopicOrPartition,
   124  		LeaderNotAvailable,
   125  		NotLeaderForPartition,
   126  		RequestTimedOut,
   127  		NetworkException,
   128  		GroupLoadInProgress,
   129  		GroupCoordinatorNotAvailable,
   130  		NotCoordinatorForGroup,
   131  		NotEnoughReplicas,
   132  		NotEnoughReplicasAfterAppend,
   133  		NotController,
   134  		KafkaStorageError,
   135  		FetchSessionIDNotFound,
   136  		InvalidFetchSessionEpoch,
   137  		ListenerNotFound,
   138  		FencedLeaderEpoch,
   139  		UnknownLeaderEpoch,
   140  		OffsetNotAvailable,
   141  		PreferredLeaderNotAvailable,
   142  		EligibleLeadersNotAvailable,
   143  		ElectionNotNeeded,
   144  		NoReassignmentInProgress,
   145  		GroupSubscribedToTopic,
   146  		UnstableOffsetCommit:
   147  		return true
   148  	default:
   149  		return false
   150  	}
   151  }
   152  
   153  // Title returns a human readable title for the error.
   154  func (e Error) Title() string {
   155  	switch e {
   156  	case Unknown:
   157  		return "Unknown"
   158  	case OffsetOutOfRange:
   159  		return "Offset Out Of Range"
   160  	case InvalidMessage:
   161  		return "Invalid Message"
   162  	case UnknownTopicOrPartition:
   163  		return "Unknown Topic Or Partition"
   164  	case InvalidMessageSize:
   165  		return "Invalid Message Size"
   166  	case LeaderNotAvailable:
   167  		return "Leader Not Available"
   168  	case NotLeaderForPartition:
   169  		return "Not Leader For Partition"
   170  	case RequestTimedOut:
   171  		return "Request Timed Out"
   172  	case BrokerNotAvailable:
   173  		return "Broker Not Available"
   174  	case ReplicaNotAvailable:
   175  		return "Replica Not Available"
   176  	case MessageSizeTooLarge:
   177  		return "Message Size Too Large"
   178  	case StaleControllerEpoch:
   179  		return "Stale Controller Epoch"
   180  	case OffsetMetadataTooLarge:
   181  		return "Offset Metadata Too Large"
   182  	case GroupLoadInProgress:
   183  		return "Group Load In Progress"
   184  	case GroupCoordinatorNotAvailable:
   185  		return "Group Coordinator Not Available"
   186  	case NotCoordinatorForGroup:
   187  		return "Not Coordinator For Group"
   188  	case InvalidTopic:
   189  		return "Invalid Topic"
   190  	case RecordListTooLarge:
   191  		return "Record List Too Large"
   192  	case NotEnoughReplicas:
   193  		return "Not Enough Replicas"
   194  	case NotEnoughReplicasAfterAppend:
   195  		return "Not Enough Replicas After Append"
   196  	case InvalidRequiredAcks:
   197  		return "Invalid Required Acks"
   198  	case IllegalGeneration:
   199  		return "Illegal Generation"
   200  	case InconsistentGroupProtocol:
   201  		return "Inconsistent Group Protocol"
   202  	case InvalidGroupId:
   203  		return "Invalid Group ID"
   204  	case UnknownMemberId:
   205  		return "Unknown Member ID"
   206  	case InvalidSessionTimeout:
   207  		return "Invalid Session Timeout"
   208  	case RebalanceInProgress:
   209  		return "Rebalance In Progress"
   210  	case InvalidCommitOffsetSize:
   211  		return "Invalid Commit Offset Size"
   212  	case TopicAuthorizationFailed:
   213  		return "Topic Authorization Failed"
   214  	case GroupAuthorizationFailed:
   215  		return "Group Authorization Failed"
   216  	case ClusterAuthorizationFailed:
   217  		return "Cluster Authorization Failed"
   218  	case InvalidTimestamp:
   219  		return "Invalid Timestamp"
   220  	case UnsupportedSASLMechanism:
   221  		return "Unsupported SASL Mechanism"
   222  	case IllegalSASLState:
   223  		return "Illegal SASL State"
   224  	case UnsupportedVersion:
   225  		return "Unsupported Version"
   226  	case TopicAlreadyExists:
   227  		return "Topic Already Exists"
   228  	case InvalidPartitionNumber:
   229  		return "Invalid Partition Number"
   230  	case InvalidReplicationFactor:
   231  		return "Invalid Replication Factor"
   232  	case InvalidReplicaAssignment:
   233  		return "Invalid Replica Assignment"
   234  	case InvalidConfiguration:
   235  		return "Invalid Configuration"
   236  	case NotController:
   237  		return "Not Controller"
   238  	case InvalidRequest:
   239  		return "Invalid Request"
   240  	case UnsupportedForMessageFormat:
   241  		return "Unsupported For Message Format"
   242  	case PolicyViolation:
   243  		return "Policy Violation"
   244  	case OutOfOrderSequenceNumber:
   245  		return "Out Of Order Sequence Number"
   246  	case DuplicateSequenceNumber:
   247  		return "Duplicate Sequence Number"
   248  	case InvalidProducerEpoch:
   249  		return "Invalid Producer Epoch"
   250  	case InvalidTransactionState:
   251  		return "Invalid Transaction State"
   252  	case InvalidProducerIDMapping:
   253  		return "Invalid Producer ID Mapping"
   254  	case InvalidTransactionTimeout:
   255  		return "Invalid Transaction Timeout"
   256  	case ConcurrentTransactions:
   257  		return "Concurrent Transactions"
   258  	case TransactionCoordinatorFenced:
   259  		return "Transaction Coordinator Fenced"
   260  	case TransactionalIDAuthorizationFailed:
   261  		return "Transactional ID Authorization Failed"
   262  	case SecurityDisabled:
   263  		return "Security Disabled"
   264  	case BrokerAuthorizationFailed:
   265  		return "Broker Authorization Failed"
   266  	case KafkaStorageError:
   267  		return "Kafka Storage Error"
   268  	case LogDirNotFound:
   269  		return "Log Dir Not Found"
   270  	case SASLAuthenticationFailed:
   271  		return "SASL Authentication Failed"
   272  	case UnknownProducerId:
   273  		return "Unknown Producer ID"
   274  	case ReassignmentInProgress:
   275  		return "Reassignment In Progress"
   276  	case DelegationTokenAuthDisabled:
   277  		return "Delegation Token Auth Disabled"
   278  	case DelegationTokenNotFound:
   279  		return "Delegation Token Not Found"
   280  	case DelegationTokenOwnerMismatch:
   281  		return "Delegation Token Owner Mismatch"
   282  	case DelegationTokenRequestNotAllowed:
   283  		return "Delegation Token Request Not Allowed"
   284  	case DelegationTokenAuthorizationFailed:
   285  		return "Delegation Token Authorization Failed"
   286  	case DelegationTokenExpired:
   287  		return "Delegation Token Expired"
   288  	case InvalidPrincipalType:
   289  		return "Invalid Principal Type"
   290  	case NonEmptyGroup:
   291  		return "Non Empty Group"
   292  	case GroupIdNotFound:
   293  		return "Group ID Not Found"
   294  	case FetchSessionIDNotFound:
   295  		return "Fetch Session ID Not Found"
   296  	case InvalidFetchSessionEpoch:
   297  		return "Invalid Fetch Session Epoch"
   298  	case ListenerNotFound:
   299  		return "Listener Not Found"
   300  	case TopicDeletionDisabled:
   301  		return "Topic Deletion Disabled"
   302  	case FencedLeaderEpoch:
   303  		return "Fenced Leader Epoch"
   304  	case UnknownLeaderEpoch:
   305  		return "Unknown Leader Epoch"
   306  	case UnsupportedCompressionType:
   307  		return "Unsupported Compression Type"
   308  	case EligibleLeadersNotAvailable:
   309  		return "Eligible Leader Not Available"
   310  	case ElectionNotNeeded:
   311  		return "Election Not Needed"
   312  	case NoReassignmentInProgress:
   313  		return "No Reassignment In Progress"
   314  	case GroupSubscribedToTopic:
   315  		return "Group Subscribed To Topic"
   316  	case InvalidRecord:
   317  		return "Invalid Record"
   318  	case UnstableOffsetCommit:
   319  		return "Unstable Offset Commit"
   320  	}
   321  	return ""
   322  }
   323  
   324  // Description returns a human readable description of cause of the error.
   325  func (e Error) Description() string {
   326  	switch e {
   327  	case Unknown:
   328  		return "an unexpected server error occurred"
   329  	case OffsetOutOfRange:
   330  		return "the requested offset is outside the range of offsets maintained by the server for the given topic/partition"
   331  	case InvalidMessage:
   332  		return "the message contents does not match its CRC"
   333  	case UnknownTopicOrPartition:
   334  		return "the request is for a topic or partition that does not exist on this broker"
   335  	case InvalidMessageSize:
   336  		return "the message has a negative size"
   337  	case LeaderNotAvailable:
   338  		return "the cluster is in the middle of a leadership election and there is currently no leader for this partition and hence it is unavailable for writes"
   339  	case NotLeaderForPartition:
   340  		return "the client attempted to send messages to a replica that is not the leader for some partition, the client's metadata are likely out of date"
   341  	case RequestTimedOut:
   342  		return "the request exceeded the user-specified time limit in the request"
   343  	case BrokerNotAvailable:
   344  		return "not a client facing error and is used mostly by tools when a broker is not alive"
   345  	case ReplicaNotAvailable:
   346  		return "a replica is expected on a broker, but is not (this can be safely ignored)"
   347  	case MessageSizeTooLarge:
   348  		return "the server has a configurable maximum message size to avoid unbounded memory allocation and the client attempted to produce a message larger than this maximum"
   349  	case StaleControllerEpoch:
   350  		return "internal error code for broker-to-broker communication"
   351  	case OffsetMetadataTooLarge:
   352  		return "the client specified a string larger than configured maximum for offset metadata"
   353  	case GroupLoadInProgress:
   354  		return "the broker returns this error code for an offset fetch request if it is still loading offsets (after a leader change for that offsets topic partition), or in response to group membership requests (such as heartbeats) when group metadata is being loaded by the coordinator"
   355  	case GroupCoordinatorNotAvailable:
   356  		return "the broker returns this error code for group coordinator requests, offset commits, and most group management requests if the offsets topic has not yet been created, or if the group coordinator is not active"
   357  	case NotCoordinatorForGroup:
   358  		return "the broker returns this error code if it receives an offset fetch or commit request for a group that it is not a coordinator for"
   359  	case InvalidTopic:
   360  		return "a request which attempted to access an invalid topic (e.g. one which has an illegal name), or if an attempt was made to write to an internal topic (such as the consumer offsets topic)"
   361  	case RecordListTooLarge:
   362  		return "a message batch in a produce request exceeds the maximum configured segment size"
   363  	case NotEnoughReplicas:
   364  		return "the number of in-sync replicas is lower than the configured minimum and requiredAcks is -1"
   365  	case NotEnoughReplicasAfterAppend:
   366  		return "the message was written to the log, but with fewer in-sync replicas than required."
   367  	case InvalidRequiredAcks:
   368  		return "the requested requiredAcks is invalid (anything other than -1, 1, or 0)"
   369  	case IllegalGeneration:
   370  		return "the generation id provided in the request is not the current generation"
   371  	case InconsistentGroupProtocol:
   372  		return "the member provided a protocol type or set of protocols which is not compatible with the current group"
   373  	case InvalidGroupId:
   374  		return "the group id is empty or null"
   375  	case UnknownMemberId:
   376  		return "the member id is not in the current generation"
   377  	case InvalidSessionTimeout:
   378  		return "the requested session timeout is outside of the allowed range on the broker"
   379  	case RebalanceInProgress:
   380  		return "the coordinator has begun rebalancing the group, the client should rejoin the group"
   381  	case InvalidCommitOffsetSize:
   382  		return "an offset commit was rejected because of oversize metadata"
   383  	case TopicAuthorizationFailed:
   384  		return "the client is not authorized to access the requested topic"
   385  	case GroupAuthorizationFailed:
   386  		return "the client is not authorized to access a particular group id"
   387  	case ClusterAuthorizationFailed:
   388  		return "the client is not authorized to use an inter-broker or administrative API"
   389  	case InvalidTimestamp:
   390  		return "the timestamp of the message is out of acceptable range"
   391  	case UnsupportedSASLMechanism:
   392  		return "the broker does not support the requested SASL mechanism"
   393  	case IllegalSASLState:
   394  		return "the request is not valid given the current SASL state"
   395  	case UnsupportedVersion:
   396  		return "the version of API is not supported"
   397  	case TopicAlreadyExists:
   398  		return "a topic with this name already exists"
   399  	case InvalidPartitionNumber:
   400  		return "the number of partitions is invalid"
   401  	case InvalidReplicationFactor:
   402  		return "the replication-factor is invalid"
   403  	case InvalidReplicaAssignment:
   404  		return "the replica assignment is invalid"
   405  	case InvalidConfiguration:
   406  		return "the configuration is invalid"
   407  	case NotController:
   408  		return "this is not the correct controller for this cluster"
   409  	case InvalidRequest:
   410  		return "this most likely occurs because of a request being malformed by the client library or the message was sent to an incompatible broker, se the broker logs for more details"
   411  	case UnsupportedForMessageFormat:
   412  		return "the message format version on the broker does not support the request"
   413  	case PolicyViolation:
   414  		return "the request parameters do not satisfy the configured policy"
   415  	case OutOfOrderSequenceNumber:
   416  		return "the broker received an out of order sequence number"
   417  	case DuplicateSequenceNumber:
   418  		return "the broker received a duplicate sequence number"
   419  	case InvalidProducerEpoch:
   420  		return "the producer attempted an operation with an old epoch, either there is a newer producer with the same transactional ID, or the producer's transaction has been expired by the broker"
   421  	case InvalidTransactionState:
   422  		return "the producer attempted a transactional operation in an invalid state"
   423  	case InvalidProducerIDMapping:
   424  		return "the producer attempted to use a producer id which is not currently assigned to its transactional ID"
   425  	case InvalidTransactionTimeout:
   426  		return "the transaction timeout is larger than the maximum value allowed by the broker (as configured by max.transaction.timeout.ms)"
   427  	case ConcurrentTransactions:
   428  		return "the producer attempted to update a transaction while another concurrent operation on the same transaction was ongoing"
   429  	case TransactionCoordinatorFenced:
   430  		return "the transaction coordinator sending a WriteTxnMarker is no longer the current coordinator for a given producer"
   431  	case TransactionalIDAuthorizationFailed:
   432  		return "the transactional ID authorization failed"
   433  	case SecurityDisabled:
   434  		return "the security features are disabled"
   435  	case BrokerAuthorizationFailed:
   436  		return "the broker authorization failed"
   437  	case KafkaStorageError:
   438  		return "disk error when trying to access log file on the disk"
   439  	case LogDirNotFound:
   440  		return "the user-specified log directory is not found in the broker config"
   441  	case SASLAuthenticationFailed:
   442  		return "SASL Authentication failed"
   443  	case UnknownProducerId:
   444  		return "the broker could not locate the producer metadata associated with the producer ID"
   445  	case ReassignmentInProgress:
   446  		return "a partition reassignment is in progress"
   447  	case DelegationTokenAuthDisabled:
   448  		return "delegation token feature is not enabled"
   449  	case DelegationTokenNotFound:
   450  		return "delegation token is not found on server"
   451  	case DelegationTokenOwnerMismatch:
   452  		return "specified principal is not valid owner/renewer"
   453  	case DelegationTokenRequestNotAllowed:
   454  		return "delegation token requests are not allowed on plaintext/1-way ssl channels and on delegation token authenticated channels"
   455  	case DelegationTokenAuthorizationFailed:
   456  		return "delegation token authorization failed"
   457  	case DelegationTokenExpired:
   458  		return "delegation token is expired"
   459  	case InvalidPrincipalType:
   460  		return "supplied principaltype is not supported"
   461  	case NonEmptyGroup:
   462  		return "the group is not empty"
   463  	case GroupIdNotFound:
   464  		return "the group ID does not exist"
   465  	case FetchSessionIDNotFound:
   466  		return "the fetch session ID was not found"
   467  	case InvalidFetchSessionEpoch:
   468  		return "the fetch session epoch is invalid"
   469  	case ListenerNotFound:
   470  		return "there is no listener on the leader broker that matches the listener on which metadata request was processed"
   471  	case TopicDeletionDisabled:
   472  		return "topic deletion is disabled"
   473  	case FencedLeaderEpoch:
   474  		return "the leader epoch in the request is older than the epoch on the broker"
   475  	case UnknownLeaderEpoch:
   476  		return "the leader epoch in the request is newer than the epoch on the broker"
   477  	case UnsupportedCompressionType:
   478  		return "the requesting client does not support the compression type of given partition"
   479  	case EligibleLeadersNotAvailable:
   480  		return "eligible topic partition leaders are not available"
   481  	case ElectionNotNeeded:
   482  		return "leader election not needed for topic partition"
   483  	case NoReassignmentInProgress:
   484  		return "no partition reassignment is in progress"
   485  	case GroupSubscribedToTopic:
   486  		return "deleting offsets of a topic is forbidden while the consumer group is actively subscribed to it"
   487  	case InvalidRecord:
   488  		return "this record has failed the validation on broker and hence be rejected"
   489  	case UnstableOffsetCommit:
   490  		return "there are unstable offsets that need to be cleared"
   491  	}
   492  	return ""
   493  }
   494  
   495  func isTimeout(err error) bool {
   496  	var timeoutError interface{ Timeout() bool }
   497  	if errors.As(err, &timeoutError) {
   498  		return timeoutError.Timeout()
   499  	}
   500  	return false
   501  }
   502  
   503  func isTemporary(err error) bool {
   504  	var tempError interface{ Temporary() bool }
   505  	if errors.As(err, &tempError) {
   506  		return tempError.Temporary()
   507  	}
   508  	return false
   509  }
   510  
   511  func isTransientNetworkError(err error) bool {
   512  	return errors.Is(err, io.ErrUnexpectedEOF) ||
   513  		errors.Is(err, syscall.ECONNREFUSED) ||
   514  		errors.Is(err, syscall.ECONNRESET) ||
   515  		errors.Is(err, syscall.EPIPE)
   516  }
   517  
   518  func silentEOF(err error) error {
   519  	if err == io.EOF {
   520  		err = nil
   521  	}
   522  	return err
   523  }
   524  
   525  func dontExpectEOF(err error) error {
   526  	if err == io.EOF {
   527  		err = io.ErrUnexpectedEOF
   528  	}
   529  	return err
   530  }
   531  
   532  func coalesceErrors(errs ...error) error {
   533  	for _, err := range errs {
   534  		if err != nil {
   535  			return err
   536  		}
   537  	}
   538  	return nil
   539  }
   540  
   541  type MessageTooLargeError struct {
   542  	Message   Message
   543  	Remaining []Message
   544  }
   545  
   546  func messageTooLarge(msgs []Message, i int) MessageTooLargeError {
   547  	remain := make([]Message, 0, len(msgs)-1)
   548  	remain = append(remain, msgs[:i]...)
   549  	remain = append(remain, msgs[i+1:]...)
   550  	return MessageTooLargeError{
   551  		Message:   msgs[i],
   552  		Remaining: remain,
   553  	}
   554  }
   555  
   556  func (e MessageTooLargeError) Error() string {
   557  	return MessageSizeTooLarge.Error()
   558  }
   559  
   560  func makeError(code int16, message string) error {
   561  	if code == 0 {
   562  		return nil
   563  	}
   564  	if message == "" {
   565  		return Error(code)
   566  	}
   567  	return fmt.Errorf("%w: %s", Error(code), message)
   568  }
   569  
   570  // WriteError is returned by kafka.(*Writer).WriteMessages when the writer is
   571  // not configured to write messages asynchronously. WriteError values contain
   572  // a list of errors where each entry matches the position of a message in the
   573  // WriteMessages call. The program can determine the status of each message by
   574  // looping over the error:
   575  //
   576  //	switch err := w.WriteMessages(ctx, msgs...).(type) {
   577  //	case nil:
   578  //	case kafka.WriteErrors:
   579  //		for i := range msgs {
   580  //			if err[i] != nil {
   581  //				// handle the error writing msgs[i]
   582  //				...
   583  //			}
   584  //		}
   585  //	default:
   586  //		// handle other errors
   587  //		...
   588  //	}
   589  //
   590  type WriteErrors []error
   591  
   592  // Count counts the number of non-nil errors in err.
   593  func (err WriteErrors) Count() int {
   594  	n := 0
   595  
   596  	for _, e := range err {
   597  		if e != nil {
   598  			n++
   599  		}
   600  	}
   601  
   602  	return n
   603  }
   604  
   605  func (err WriteErrors) Error() string {
   606  	return fmt.Sprintf("kafka write errors (%d/%d)", err.Count(), len(err))
   607  }