Bun HTTP breaks Sentry Tracing
What version of Bun is running?
1.0.7+b0393fba6200d8573f3433fb0af258a0e33ac157
What platform is your computer?
Darwin 23.1.0 arm64 arm
What steps can reproduce the bug?
Ref: https://github.com/getsentry/sentry-javascript/issues/9564 and https://github.com/getsentry/sentry-javascript/issues/9608
Code Sample
index.ts
import { uploadS3 } from "./files";
import * as Sentry from "@sentry/bun";
Sentry.init({
dsn: <dsn>,
tracesSampleRate: 1.0,
});
await uploadS3(
"test",
"/dev/backend/src/index.ts",
"text/plain"
);
files.ts
import {
S3Client,
} from "@aws-sdk/client-s3";
import * as Sentry from "@sentry/bun";
import { Upload } from "@aws-sdk/lib-storage";
import { createReadStream } from "node:fs";
const s3 = new S3Client({
logger: console,
});
s3.middlewareStack.add((next) => async (args) => {
console.log("s3 request", args);
const result = await next(args);
console.log("s3 response", result);
return result;
});
const bucketName = <bucketName>
export const uploadS3 = async (
fileId: string,
fpath: string,
mimeType: string
) => {
console.log(
"uploading file to S3",
fileId,
fpath,
bucketName,
mimeType,
);
try {
const upload = new Upload({
client: s3,
params: {
Bucket: bucketName,
Key: fileId,
Body: createReadStream(fpath),
},
queueSize: 4,
});
return upload.done();
} catch (err) {
console.error("error uploading file to S3", err);
Sentry.captureException(err);
}
};
package.json
{
"name": "backend",
"version": "1.0.50",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "bun run --watch src/index.ts"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.451.0",
"@aws-sdk/lib-storage": "^3.454.0",
"@sentry/bun": "^7.80.1",
},
"devDependencies": {
"bun-types": "latest"
},
"module": "src/index.js"
}
What is the expected behavior?
File is uploaded to S3 successfully, action is logged to Sentry.
What do you see instead?
Request is never completed. It doesn't timeout either, just keeps the client waiting. AFAIK I understand it, the S3 client doesn't even get a response so not sure if the file upload request is even sent.
Logs:
uploading file to S3 test /dev/backend/src/index.ts <bucketName> text/plain
s3 request {
middlewareStack: {
add: [Function: add],
addRelativeTo: [Function: addRelativeTo],
clone: [Function: clone],
use: [Function: use],
remove: [Function: remove],
removeByTag: [Function: removeByTag],
concat: [Function: concat],
applyToStack: [Function: cloneTo],
identify: [Function: identify],
identifyOnResolve: [Function: identifyOnResolve],
resolve: [Function: resolve]
},
input: {
Bucket: <bucket>,
Key: "test",
Body: Buffer(2205) [ 105, 109, 112, 111, 114, 116, 32, 123, 32, 69, 108, 121, 115, 105, 97, 44, 32, 116, 32, 125, 32, 102, 114, 111, 109, 32, 34, 101, 108, 121, 115, 105, 97, 34, 59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 99, 114, 101, 97, 116, 101, 65, 117, 116, 104, 48, 85, 115, 101, 114, 32, 125, 32, 102, 114, 111, 109, 32, 34, 46, 47, 109, 111, 100, 117, 108, 101, 115, 47, 97, 117, 116, 104, 48, 34, 59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 103, 101, 116, 68, 114, 105, 118, 101, 67, 108, 105, 101, 110, 116, 44, 32, 117, 112, 108, 111, 97, 100, 70, 105, 108, 101, 84, 111, 71, 111, 111, 103, 108, 101, 68, 114, 105, 118, 101, 32, 125, 32, 102, 114, 111, 109, 32, 34, 46, 47, 109, 111, 100, 117, 108, 101, 115, 47, 103, 100, 114, 105, 118, 101, 34, 59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 100, 111, 119, 110, 108, 111, 97, 100, 70, 105, 108, 101, 44, 32, 117, 112, 108, 111, 97, 100, 70, 105, 108, 101, 32, 125, 32, 102, 114, 111, 109, 32, 34, 46, 47, 109, 111, 100, 117, 108, 101, 115, 47, 102, 105, 108, 101, 115, 34, 59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 105, 115, 73, 110, 116, 101, 114, 110, 97, 108, 65, 112, 112, 32, 125, 32, 102, 114, 111, 109, 32, 34, 46, 47, 109, 111, 100, 117, 108, 101, 115, 47, 109, 105, 100, 100, 108, 101, 119, 97, 114, 101, 34, 59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 115, 119, 97, 103, 103, 101, 114, 32, 125, 32, 102, 114, 111, 109, 32, 34, 64, 101, 108, 121, 115, 105, 97, 106, 115, 47, 115, 119, 97, 103, 103, 101, 114, 34, 59, 10, 105, 109, 112, 111, 114, 116, 32, 42, 32, 97, 115, 32, 83, 101, 110, 116, 114, 121, 32, 102, 114, 111, 109, 32, 34, 64, 115, 101, 110, 116, 114, 121, 47, 98, 117, 110, 34, 59, 10, 105, 109, 112, 111, 114, 116, 32, 123, 32, 99, 111, 114, 115, 32, 125, 32, 102, 114, 111, 109, 32, 34, 64, 101, 108, 121, 115, 105, 97, 106, 115, 47, 99, 111, 114, 115, 34, 59, 10, 10, 105, 102, 32, 40, 112, 114, 111, 99, 101, 115, 115, 46, 101, 110, 118, 46, 78, 79, 68, 69, 95, 69, 78, 86, 32, 61, 61, 61, 32, 34, 112, 114, 111, 100, 117, 99, 116, 105, 111, 110, 34, 41, 32, 123, 10, 32, 32, 83, 101, 110, 116, 114, 121, 46, 105, 110, 105, 116, 40, 123, 10, 32, 32, 32, 32, 100, 115, 110, 58, 32, 34, 104, 116, 116, 112, 115, 58, 47, 47, 52, 99, 102, 52, 98, 102, 53, 51, 57, 53, 51, 57, 56, 101, 97, 97, 56, 100, 54, 49, 98, 99, 51, 97, 102, 98, 54, 53, 53, 54, 52, 49, 64, ... 1692 more ]
}
}
endpoints Initial EndpointParams: {
"Bucket": <bucket>,
"ForcePathStyle": false,
"UseArnRegion": false,
"DisableMultiRegionAccessPoints": false,
"Accelerate": false,
"UseGlobalEndpoint": false,
"UseFIPS": false,
"Region": "us-west-2",
"UseDualStack": false
}
endpoints evaluateCondition: isSet($Region) = true
endpoints evaluateCondition: booleanEquals($Accelerate, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($UseFIPS, true) = false
endpoints evaluateCondition: isSet($Bucket) = true
endpoints evaluateCondition: substring($Bucket, 49, 50, true) = null
endpoints evaluateCondition: isSet($Bucket) = true
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($ForcePathStyle, false) = true
endpoints evaluateCondition: aws.isVirtualHostableS3Bucket($Bucket, false) = true
endpoints evaluateCondition: aws.partition($Region) = {
"dnsSuffix": "amazonaws.com",
"dualStackDnsSuffix": "api.aws",
"implicitGlobalRegion": "us-east-1",
"name": "aws",
"supportsDualStack": true,
"supportsFIPS": true,
"description": "US West (Oregon)"
}
endpoints assign: partitionResult := {
"dnsSuffix": "amazonaws.com",
"dualStackDnsSuffix": "api.aws",
"implicitGlobalRegion": "us-east-1",
"name": "aws",
"supportsDualStack": true,
"supportsFIPS": true,
"description": "US West (Oregon)"
}
endpoints evaluateCondition: isValidHostLabel($Region, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: isSet($Endpoint) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: not(isSet($Endpoint)) = true
endpoints evaluateCondition: stringEquals($Region, aws-global) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: not(isSet($Endpoint)) = true
endpoints evaluateCondition: not(stringEquals($Region, aws-global)) = true
endpoints evaluateCondition: booleanEquals($UseGlobalEndpoint, true) = false
endpoints evaluateCondition: booleanEquals($UseDualStack, false) = true
endpoints evaluateCondition: booleanEquals($UseFIPS, false) = true
endpoints evaluateCondition: booleanEquals($Accelerate, false) = true
endpoints evaluateCondition: not(isSet($Endpoint)) = true
endpoints evaluateCondition: not(stringEquals($Region, aws-global)) = true
endpoints evaluateCondition: booleanEquals($UseGlobalEndpoint, false) = true
endpoints Resolving endpoint from template: {
"url": "https://{Bucket}.s3.{Region}.{partitionResult#dnsSuffix}",
"properties": {
"authSchemes": [
{
"disableDoubleEncoding": true,
"name": "sigv4",
"signingName": "s3",
"signingRegion": "{Region}"
}
]
},
"headers": {}
}
endpoints Resolved endpoint: {
"headers": {},
"properties": {
"authSchemes": [
{
"disableDoubleEncoding": true,
"name": "sigv4",
"signingName": "s3",
"signingRegion": "us-west-2"
}
]
},
"url": "https://<bucket>.s3.us-west-2.amazonaws.com/"
}
Additional information
Seems like a Bun issue from https://github.com/getsentry/sentry-javascript/issues/9564#issuecomment-1841082305 Removing the HTTP integration from Sentry fixes the issue for now, but we lose some logs we really need
Sentry.init({
dsn: <dsn>,
tracesSampleRate: 1.0,
debug: true,
integrations: (int) =>
int.filter((i) => !["Http"].includes(i.name)),
});
Here is the problem: https://github.com/oven-sh/bun/issues/5091
experiencing this also with:
@sentry/bun version 7.93.0bun version 1.0.20
Can I ask, is this an issue with the Sentry SDK, like does it work if you remove/disable Sentry?
Can I ask, is this an issue with the Sentry SDK, like does it work if you remove/disable Sentry?
Disabling sentry fixes the issue for me (commenting out Sentry.init or adding this line to the Sentry.init config object: integrations: (int) => int.filter((i) => !["BunServer", "Http"].includes(i.name)), - as shown in the original issue)
The response on the relevant sentry issue was that since their monkey patching works for node that this must be an issue with bun
Hello! Thanks for all of your hard work. @Jarred-Sumner I think lots of teams are eager to move to Bun but can't due this issue, do you know when we can expect a fix for this? 🥲 Thanks again!
We changed how we do monkeypatching of HTTP in our upcoming new Sentry JavaScript SDKs major version, 8.0.
Currently there is a beta release: https://github.com/getsentry/sentry-javascript/releases/tag/8.0.0-beta.1
This means you can use Sentry with the v8 beta and tracing should work with Bun!
Fixed with 8.0.0 of @sentry/bun - please give it a try. Thanks!
https://docs.sentry.io/platforms/javascript/guides/bun
https://docs.sentry.io/platforms/javascript/guides/bun/migration/v7-to-v8
@AbhiPrasad Does this use the latest changes from v1.1.8?
@AbhiPrasad Does this use the latest changes from v1.1.8?
Yes!
PR here: https://github.com/getsentry/sentry-javascript/pull/11960