apache/beam · error
Failed to extend visibility timeout for
Error message
Failed to extend visibility timeout for {} messages with expired receipt handles. What it means
WARN logged by the SQS unbounded reader when a ChangeMessageVisibilityBatch response contains failures whose receipt handles have expired: those messages can no longer have their visibility timeout extended and will be redelivered by SQS. The reader partitions failures by handle validity and drops the expired ones from its pending-extend tracking (numExtendedDeadlines only counts real successes), relying on SQS at-least-once redelivery instead.
Solutions
- No code change needed for expired handles: SQS redelivers those messages and the reader reprocesses them
- If expiry is premature, extend visibility timeout earlier (smaller extension intervals) or increase the initial visibility timeout on the queue
- Make the downstream pipeline idempotent since redelivery means possible duplicates
Defensive patterns
Strategy: fallback
When it happens
Trigger: Thrown at sdks/java/io/amazon-web-services2/src/main/java/org/apache/beam/sdk/io/aws2/sqs/SqsUnboundedReader.java:861 when the library encounters an invalid state.
Common situations: See trigger scenarios.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
AI-assisted analysis of apache/beam@12126d8942 (2026-09-13).
Data as JSON: /api/errors/6c09a28eb7413973.
Report an issue: GitHub.
Appendix: source
Thrown at sdks/java/io/amazon-web-services2/src/main/java/org/apache/beam/sdk/io/aws2/sqs/SqsUnboundedReader.java:861
response.failed().stream()
.collect(partitioningBy(this::isHandleInvalid, mapping(e -> e.id(), toSet())));
// Keep failed IDs only, but discard invalid (expired) receipt handles
pendingExtends.keySet().retainAll(failures.getOrDefault(FALSE, ImmutableSet.of()));
// Skip stats update and inFlight management if explicitly expiring messages for immediate
// redelivery
if (extensionSec > 0) {
numExtendedDeadlines.add(nowMsSinceEpoch, response.successful().size());
Set<String> invalidMsgIds = failures.getOrDefault(TRUE, ImmutableSet.of());
if (invalidMsgIds.size() > 0) {
// consider invalid (expired) messages no longer in flight
numLateDeadlines.add(nowMsSinceEpoch, invalidMsgIds.size());
for (String msgId : invalidMsgIds) {
inFlight.remove(msgId);
}
LOG.warn(
"Failed to extend visibility timeout for {} messages with expired receipt handles.",
invalidMsgIds.size());
}
}
retries += 1;
}
}
@VisibleForTesting
long getVisibilityTimeoutMs() {
return visibilityTimeoutMs;
}
/** Log stats if time to do so. */
private void stats() {
long nowMsSinceEpoch = now();
if (lastLogTimestampMsSinceEpoch < 0) {View on GitHub (pinned to 12126d8942)