{"record":{"id":"45d19aa159397f4b","repo":"signalapp/Signal-Server","slug":"exceeded-maximum-uploadlength","errorCode":null,"errorMessage":"exceeded maximum uploadLength","messagePattern":"exceeded maximum uploadLength","errorType":"http","errorClass":"ClientErrorException","httpStatus":413,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/controllers/ArchiveController.java","lineNumber":613,"sourceCode":"      @HeaderParam(X_SIGNAL_ZK_AUTH_SIGNATURE) final BackupAuthCredentialPresentationSignature signature,\n\n      @Parameter(description = \"The size of the message backup to upload in bytes\")\n      @QueryParam(\"uploadLength\") final Optional<Long> uploadLength)\n      throws BackupFailedZkAuthenticationException, BackupWrongCredentialTypeException, BackupPermissionException {\n    if (account.isPresent()) {\n      throw new BadRequestException(\"must not use authenticated connection for anonymous operations\");\n    }\n\n    final AuthenticatedBackupUser backupUser =\n        backupManager.authenticateBackupUser(presentation.presentation, signature.signature, userAgent);\n\n    final boolean oversize = uploadLength\n        .map(length -> length > maxMessageBackupSize)\n        .orElse(false);\n\n    backupMetrics.updateMessageBackupSizeDistribution(backupUser, oversize, uploadLength);\n    if (oversize) {\n      throw new ClientErrorException(\"exceeded maximum uploadLength\", Response.Status.REQUEST_ENTITY_TOO_LARGE);\n    }\n    final BackupUploadDescriptor uploadDescriptor =\n        backupManager.createMessageBackupUploadDescriptor(backupUser, uploadLength.orElse(maxMessageBackupSize));\n    return new UploadDescriptorResponse(\n        uploadDescriptor.cdn(),\n        uploadDescriptor.key(),\n        uploadDescriptor.headers(),\n        uploadDescriptor.signedUploadLocation());\n  }\n\n  @GET\n  @Path(\"/media/upload/form\")\n  @Produces(MediaType.APPLICATION_JSON)\n  @Operation(\n      summary = \"Fetch media attachment upload form\",\n      description = \"\"\"\n          Retrieve an upload form that can be used to perform a resumable upload of an attachment. After uploading, the\n          attachment can be copied into the backup at PUT /archives/media/.","sourceCodeStart":595,"sourceCodeEnd":631,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/controllers/ArchiveController.java#L595-L631","documentation":"Before creating a message-backup upload descriptor, the controller validates the declared uploadLength against maxMessageBackupSize. If the declared size exceeds the limit, it throws ClientErrorException with HTTP 413 REQUEST_ENTITY_TOO_LARGE. The check uses the query parameter, not the actual body, so clients must declare their size honestly.","triggerScenarios":"Calling the backup upload endpoint with ?uploadLength= greater than maxMessageBackupSize.","commonSituations":"Backups growing after a server-side limit reduction; clients rounding up or defaulting to an oversized length; uploading a full backup where only media quota differs; version skew between client assumption and server limit.","solutions":["Reduce uploadLength to at most maxMessageBackupSize (obtain the current limit from the server's advertised max).","Free space by removing old backups before re-uploading.","Split the backup or upgrade the client to the latest version that respects current limits.","If using uploadLength-less requests (default = max size), pass an explicit accurate length."],"exampleFix":"// before\nlong length = backupBytes.length + extraAttachmentsBytes; // exceeds server max -> 413\n// after\nlong length = backupBytes.length;\nif (length > maxMessageBackupSize) {\n  throw new BackupTooLargeException(); // surface to user before calling server\n}","handlingStrategy":"validation","validationCode":"long actual = backupBytes.length;\nif (actual > maxMessageBackupSize) {\n  throw new BackupTooLargeException(actual, maxMessageBackupSize); // fail before calling server\n}","typeGuard":null,"tryCatchPattern":"try {\n  createUploadDescriptor(uploadLength);\n} catch (ClientErrorException e) {\n  if (e.getResponse().getStatus() == 413) {\n    handleBackupTooLarge();\n  } else throw e;\n}","preventionTips":["Measure exact backup bytes instead of estimating or padding.","Handle 413 by pruning old backups and retrying.","Fetch the current server limit at runtime rather than hardcoding."],"tags":["http-413","payload-size","validation","signal"],"backgroundTag":"payload-too-large","analyzedSha":"100ab61c82627582c867d19e1c0561ba2781e927","analyzedAt":"2026-09-09T13:29:47.883Z","contentChangedAt":"2026-09-09T13:29:47.883Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}