DynamoDB Streams: ExpiredIteratorException

En bref — Un itérateur de shard de GetShardIterator n'est valide que 15 minutes. Si ton consommateur s'est mis en pause, a traité un lot lentement, ou a conservé un itérateur au travers d'un redémarrage, le prochain appel GetRecords lève ceci. Récupère en demandant un nouvel itérateur — utilise AFTER_SEQUENCE_NUMBER avec le dernier numéro de séquence traité pour reprendre exactement là où tu t'es arrêté.

Ce que ça signifie

ExpiredIteratorException: The provided iterator exceeds the maximum age allowed.

Lire un flux DynamoDB directement est une boucle en deux étapes : GetShardIterator te donne une poignée de position dans un shard, et chaque appel GetRecords la consomme et renvoie la suivante (NextShardIterator). Chacune de ces poignées expire 15 minutes après son émission. L'exception ne signifie pas que les données ont disparu — les enregistrements du flux vivent 24 heures — elle signifie seulement que cette poignée de position est périmée et qu'il t'en faut une nouvelle.

Pourquoi ça arrive

  • Traitement lent entre les scrutations — le travail effectué par lot (écritures, appels externes) prend plus de 15 minutes avant le prochain GetRecords.
  • Un consommateur en pause ou suspendu — un worker arrêté, un déploiement long, ou une session de débogueur qui retient la boucle.
  • Stocker les itérateurs — persister la chaîne de l'itérateur (dans une BD ou un checkpoint) et la réutiliser plus tard ; les itérateurs sont éphémères, les numéros de séquence non.
  • Backoff trop long — une boucle de réessai sur erreur qui a dormi au-delà de la fenêtre.

Comment corriger

  1. Attrape-la et ré-amorce l'itérateur depuis ton dernier checkpoint — suis le SequenceNumber du dernier enregistrement traité, puis :

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

    Pas encore de checkpoint ? TRIM_HORIZON retraite le shard depuis l'enregistrement disponible le plus ancien ; LATEST saute à la nouvelle activité.

  2. Fais des checkpoints sur les numéros de séquence, jamais sur les itérateurs — le numéro de séquence est le point de reprise durable.

  3. Garde la boucle de scrutation serrée — fais le travail lourd par enregistrement de façon asynchrone (mets-le en file) pour que la cadence de GetRecords reste bien en deçà de 15 minutes.

  4. Préfère les consommateurs managés — les mappings de source d'événements Lambda et le DynamoDB Streams Kinesis Adapter (KCL) gèrent les itérateurs et les checkpoints pour toi ; les boucles GetRecords faites main sont là où vit cette exception.

Assure-toi que ton traitement est idempotent : reprendre depuis un checkpoint peut re-livrer un enregistrement que tu avais à moitié traité. Le flux lui-même contient chaque enregistrement exactement une fois, mais un consommateur qui ré-amorce depuis son dernier checkpoint traite de fait en at-least-once.

Déboguer ce qu'un flux a réellement émis est bien plus facile quand tu peux voir les éléments changer — l'application de bureau DynoTable montre l'état en direct d'un élément pour que tu puisses recouper les enregistrements du flux avec les données. Tu estimes le coût de lecture d'un rejeu de rattrapage ? Le calculateur de tarification DynamoDB est là pour ça.

Erreurs liées

Références

Dernière vérification le 2026-07-13 par rapport à la documentation officielle AWS liée ci-dessus.

Travaille avec DynamoDB sans la Console

DynoTable est un client de bureau rapide pour DynamoDB — parcours les tables, exécute des requêtes de style SQL et édite les items en local.