grpc/grpc-java · error · GeneralSecurityException

Counter has overflowed.

Error message

Counter has overflowed.

What it means

ALTS message encryption uses a sequence counter that must never repeat. When incrementCounter() detects the counter reaching its overflow length (all bytes already at max via carry propagation), it restores the old counter value and throws GeneralSecurityException so encrypt/decrypt keep failing rather than reusing a counter value — which would break the confidentiality/integrity guarantees of the AEAD key.

Source

Thrown at alts/src/main/java/io/grpc/alts/internal/AltsChannelCrypter.java:140

  public void destroy() {
    // no destroy required
  }

  /** Increments {@code counter}, store the unincremented value in {@code oldCounter}. */
  static void incrementCounter(byte[] counter, byte[] oldCounter) throws GeneralSecurityException {
    System.arraycopy(counter, 0, oldCounter, 0, counter.length);
    int i = 0;
    for (; i < COUNTER_OVERFLOW_LENGTH; i++) {
      counter[i]++;
      if (counter[i] != (byte) 0x00) {
        break;
      }
    }

    if (i == COUNTER_OVERFLOW_LENGTH) {
      // Restore old counter value to ensure that encrypt and decrypt keep failing.
      System.arraycopy(oldCounter, 0, counter, 0, counter.length);
      throw new GeneralSecurityException("Counter has overflowed.");
    }
  }

  /** Increments the input counter, returning the previous (unincremented) value. */
  private byte[] incrementInCounter() throws GeneralSecurityException {
    incrementCounter(inCounter, oldCounter);
    return oldCounter;
  }

  /** Increments the output counter, returning the previous (unincremented) value. */
  private byte[] incrementOutCounter() throws GeneralSecurityException {
    incrementCounter(outCounter, oldCounter);
    return oldCounter;
  }

  @VisibleForTesting
  void incrementInCounterForTesting(int n) throws GeneralSecurityException {
    for (int i = 0; i < n; i++) {

View on GitHub (pinned to 64daddc1f3)

Solutions

  1. Close and re-establish the ALTS channel (new handshake generates fresh keys and counters)
  2. Catch GeneralSecurityException on the channel and treat it as terminal — the channel is unusable after overflow
  3. Reduce per-connection data volume or add application-level channel recycling for very long-lived connections

Example fix

// before
// keep using one channel forever; encrypt() eventually throws
// after
try {
  encrypt(frame);
} catch (GeneralSecurityException e) {
  channel.shutdownNow(); // rebuild channel with fresh handshake
  channel = createAltsChannel();
}
Defensive patterns

Strategy: try-catch

Validate before calling

null

Type guard

null

Try / catch

try {
  encrypt(frame);
} catch (GeneralSecurityException e) {
  channel.shutdownNow();
  channel = rebuildAltsChannel(); // fresh keys and counters
}

Prevention

When it happens

Trigger: Sending or receiving more than 2^64 (per the counter layout) ALTS frames on a single channel: encrypting the next message or decrypting an incoming frame triggers the overflow check in incrementInCounter()/incrementOutCounter().

Common situations: An extremely long-lived, high-throughput ALTS channel that processes the maximum frame count; practically unreachable in normal workloads but possible on persistent bulk-data connections.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/3a0f251a7f44ad57. Report an issue: GitHub.