DynamoDB Streams: ExpiredIteratorException

TL;DR — Um shard iterator do GetShardIterator só é válido por 15 minutos. Se seu consumidor pausou, processou um lote lentamente, ou manteve um iterator ao longo de um reinício, a próxima chamada GetRecords lança isto. Recupere-se solicitando um novo iterator — use AFTER_SEQUENCE_NUMBER com o último sequence number que você processou para retomar exatamente de onde parou.

O que significa

ExpiredIteratorException: The provided iterator exceeds the maximum age allowed.

Ler um stream do DynamoDB diretamente é um loop de dois passos: GetShardIterator te dá um handle de posição dentro de um shard, e cada chamada GetRecords o consome e retorna o próximo (NextShardIterator). Cada um desses handles expira 15 minutos depois de ser emitido. A exceção não significa que os dados sumiram — registros de stream vivem por 24 horas — ela só significa que este handle de posição está obsoleto e você precisa de um novo.

Por que acontece

  • Processamento lento entre polls — o trabalho feito por lote (escritas, chamadas externas) leva mais de 15 minutos antes do próximo GetRecords.
  • Um consumidor pausado ou suspenso — um worker parado, um deploy longo, ou uma sessão de debugger segurando o loop.
  • Armazenar iterators — persistir a string do iterator (em um banco ou checkpoint) e reutilizá-la depois; iterators são efêmeros, sequence numbers não.
  • Backoff longo demais — um loop de error-retry que dormiu além da janela.

Como corrigir

  1. Capture-a e re-semeie o iterator a partir do seu último checkpoint — rastreie o SequenceNumber do último registro que você processou, depois:

    const {ShardIterator} = await streams.send(
      new GetShardIteratorCommand({
        StreamArn: streamArn,
        ShardId: shardId,
        ShardIteratorType: 'AFTER_SEQUENCE_NUMBER',
        SequenceNumber: lastProcessedSequenceNumber
      })
    );

    Ainda sem checkpoint? TRIM_HORIZON reprocessa o shard a partir do registro disponível mais antigo; LATEST pula para a nova atividade.

  2. Faça checkpoint de sequence numbers, nunca de iterators — o sequence number é o ponto de retomada durável.

  3. Mantenha o loop de poll apertado — faça o trabalho pesado por registro de forma assíncrona (enfileire-o) para que a cadência do GetRecords fique bem dentro dos 15 minutos.

  4. Prefira consumidores gerenciados — event source mappings do Lambda e o DynamoDB Streams Kinesis Adapter (KCL) gerenciam iterators e checkpoints por você; loops de GetRecords feitos à mão são onde esta exceção vive.

Certifique-se de que seu tratamento é idempotente: retomar de um checkpoint pode reentregar um registro que você processou pela metade. O stream em si contém cada registro exatamente uma vez, mas um consumidor que re-semeia a partir de seu último checkpoint efetivamente processa pelo-menos-uma-vez.

Depurar o que um stream de fato emitiu é muito mais fácil quando você consegue ver os itens mudando — o app desktop DynoTable mostra o estado ao vivo de um item para que você possa combinar registros de stream com os dados. Estimando o custo de leitura de um replay de recuperação? A calculadora de preços do DynamoDB te dá cobertura.

Erros relacionados

Referências

Verificado pela última vez em 2026-07-13 contra a documentação oficial da AWS vinculada acima.

Trabalhe com o DynamoDB sem o Console

O DynoTable é um cliente desktop rápido para o DynamoDB — navegue pelas tabelas, execute consultas no estilo SQL e edite itens localmente.