signalapp/Signal-Server · error · IOException

S3 object too large

Error message

S3 object too large

What it means

S3ObjectMonitor.getObject enforces a maximum object size when reading the monitored S3 object. If the S3 object's content length exceeds maxObjectSize, the response is aborted and an IOException('S3 object too large') is thrown to prevent loading an unexpectedly huge object into memory. This is a safety guard for configuration data fetched from S3.

Solutions

  1. Inspect the logged sizes: compare the object's actual size to the configured maxObjectSize.
  2. Re-upload a correctly sized object to s3://<bucket>/<key>.
  3. Verify the S3 bucket/key configuration points at the intended object.
  4. If the object legitimately grew, raise the maxObjectSize configuration value deliberately.

Example fix

// before: oversized object uploaded, monitor crashes
aws s3 cp huge-config.json s3://config-bucket/keys.json

// after: enforce a sane size before upload, or raise the limit intentionally
aws s3 cp config.json s3://config-bucket/keys.json
# or in server config:
# maxObjectSize: 10485760  # raised deliberately
Defensive patterns

Strategy: validation

Validate before calling

// before pointing the monitor at an object, check its size
HeadObjectResponse head = s3.headObject(HeadObjectRequest.builder().bucket(bucket).key(objectKey).build());
if (head.contentLength() > maxObjectSize) {
  throw new IllegalStateException("Config object too large: " + head.contentLength());
}

Try / catch

try {
  monitor.refresh();
} catch (IOException e) {
  if (e.getMessage() != null && e.getMessage().contains("S3 object too large")) {
    alert.ops("Monitored S3 object oversized — check " + bucket + "/" + key);
  }
}

Prevention

When it happens

Trigger: Calling getObject()/refresh()/refreshAfterGet() when the monitored S3 object (bucket/key from config) has been replaced with content larger than the configured maxObjectSize bytes.

Common situations: Someone uploaded an oversized or wrong file to the config bucket/key, an environment pointed the monitor at the wrong S3 key, or a tool wrote concatenated/bloated data to the object.

Understand the failure class

Background: "File too large" / "file size exceeds limit" errors: why libraries cap file sizes and how to fix them — this error's family across 46 libraries.


AI-assisted analysis of signalapp/Signal-Server@100ab61c82 (2026-09-09). Data as JSON: /api/errors/2f89fcace899b034. Report an issue: GitHub.

Appendix: source

Thrown at service/src/main/java/org/whispersystems/textsecuregcm/s3/S3ObjectMonitor.java:154

   * @return the current version of the monitored S3 object.  Caller should close() this upon completion.
   * @throws IOException if the retrieved S3 object is larger than the configured maximum size
   */
  @VisibleForTesting
  ResponseInputStream<GetObjectResponse> getObject() throws IOException {
    final ResponseInputStream<GetObjectResponse> response = s3Client.getObject(GetObjectRequest.builder()
        .key(objectKey)
        .bucket(s3Bucket)
        .build());

    lastETag.set(response.response().eTag());

    if (response.response().contentLength() <= maxObjectSize) {
      return response;
    } else {
      log.warn("Object at s3://{}/{} has a size of {} bytes, which exceeds the maximum allowed size of {} bytes",
          s3Bucket, objectKey, response.response().contentLength(), maxObjectSize);
      response.abort();
      throw new IOException("S3 object too large");
    }
  }

  /**
   * Polls S3 for object metadata and notifies the listener provided at construction time if and only if the object has
   * changed since the last call to {@link #getObject()} or {@code refresh()}.
   */
  @VisibleForTesting
  void refresh(final Consumer<InputStream> changeListener) {
    try {
      final HeadObjectResponse objectMetadata = s3Client.headObject(HeadObjectRequest.builder()
          .bucket(s3Bucket)
          .key(objectKey)
          .build());

      final String initialETag = lastETag.get();
      final String refreshedETag = objectMetadata.eTag();

View on GitHub (pinned to 100ab61c82)