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
- Inspect the logged sizes: compare the object's actual size to the configured maxObjectSize.
- Re-upload a correctly sized object to s3://<bucket>/<key>.
- Verify the S3 bucket/key configuration points at the intended object.
- 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
- Gate uploads to the config bucket with a size check (CI or upload script).
- Verify bucket/key config values when deploying to a new environment.
- Keep maxObjectSize documented next to the object producer so limits stay aligned.
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)