{"record":{"id":"27dbea760f75cecf","repo":"signalapp/Signal-Server","slug":"got-a-non-200-reply-from-source-uri","errorCode":null,"errorMessage":"Got a non-200 reply from source URI: ","messagePattern":"Got a non-200 reply from source URI: ","errorType":"console","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"service/src/main/java/org/whispersystems/textsecuregcm/workers/CopyToS3Command.java","lineNumber":113,"sourceCode":"              .formatted(httpResponse.body().length, minimumExpectedSize));\n        }\n\n        final String contentType = httpResponse.headers().firstValue(\"Content-Type\").orElse(\"application/octet-stream\");\n\n        s3Client.putObject(PutObjectRequest.builder()\n            .bucket(s3Bucket)\n            .key(filename)\n            .contentType(contentType)\n            .contentLength((long) httpResponse.body().length)\n            .build(), RequestBody.fromBytes(httpResponse.body()));\n\n        logger.info(\"Copied {} bytes from {} to s3://{}/{}\",\n            httpResponse.body().length,\n            httpRequest.uri(),\n            s3Bucket,\n            filename);\n      } else {\n        throw new IOException(\"Got a non-200 reply from source URI: \" + httpResponse.statusCode());\n      }\n    }\n  }\n}\n","sourceCodeStart":95,"sourceCodeEnd":118,"githubUrl":"https://github.com/signalapp/Signal-Server/blob/100ab61c82627582c867d19e1c0561ba2781e927/service/src/main/java/org/whispersystems/textsecuregcm/workers/CopyToS3Command.java#L95-L118","documentation":"CopyToS3Command only uploads when the source server returns HTTP 200. Any other status code (404, 403, 500, redirects, etc.) causes an IOException with this message, including the actual status code, because the command does not follow non-200 flows.","triggerScenarios":"Running `copy-to-s3` against a URI that responds with any status other than 200 — the httpClient.send() completes but the else-branch throws.","commonSituations":"Typo in the source URI path; missing auth so the origin replies 403; server moved the file (404); source replying 301/302 redirect that isn't followed; upstream 5xx during maintenance.","solutions":["Verify the source URI with curl -I and confirm it returns 200","Fix authentication or credentials if the source returns 401/403","Correct the URI/path if it returns 404","Ensure the server responds 200 rather than a redirect, or point at the final URL"],"exampleFix":"// before\nhttpRequest to https://example.org/old-path\n// after\nhttpRequest to https://example.org/new-path (verified 200 via curl -I)","handlingStrategy":"validation","validationCode":"HttpRequest request = HttpRequest.newBuilder(URI.create(sourceUri)).build();\nHttpResponse<Void> probe = httpClient.send(request, HttpResponse.BodyHandlers.discarding());\nif (probe.statusCode() != 200) throw new IllegalStateException(\"source not 200: \" + probe.statusCode());","typeGuard":null,"tryCatchPattern":"try { copyToS3(...); } catch (IOException e) { logger.error(\"non-200 from {}: {}\", sourceUri, e.getMessage()); }","preventionTips":["Verify the URI returns 200 with curl -I first","Point at the final URL, not a redirect","Confirm auth/credentials for protected sources"],"tags":["network","http","cli"],"backgroundTag":"http-non-200-response","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"}