sentry-javascript icon indicating copy to clipboard operation
sentry-javascript copied to clipboard

@sentry/bun throws "TypeError: Cannot replace module namespace object's binding with configurable attribute"

Open EvHaus opened this issue 1 year ago • 16 comments

Is there an existing issue for this?

  • [X] I have checked for existing issues https://github.com/getsentry/sentry-javascript/issues
  • [X] I have reviewed the documentation https://docs.sentry.io/
  • [X] I am using the latest SDK release https://github.com/getsentry/sentry-javascript/releases

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/bun

SDK Version

8.17.0

Framework Version

Bun 1.1.18

Link to Sentry event

https://reserve-sense.sentry.io/issues/5597727361/?project=4506890995499008

SDK Setup/Reproduction Example

import { init } from '@sentry/bun';

init({
	dsn: '__MY_DSN__',
	tracesSampleRate: 0.5,
});

Steps to Reproduce

I'm adding Sentry to my Bun API and I simply added a basic init() call at the start of my server and it immediately crashes with the error below.

I'm using node-file-router and looks like combining it with the init() call causes issues. My code for that is:

import { initFileRouter } from 'node-file-router';
const runFileRouter = await initFileRouter({
	ignoreFilesRegex: [/.\.test/],
});

Expected Result

No failure

Actual Result

App crashes with:

 9 |
10 | // Sets a property on an object, preserving its enumerability.
11 | // This function assumes that the property is already writable.
12 | function defineProperty (obj, name, value) {
13 |   var enumerable = !!obj[name] && obj.propertyIsEnumerable(name)
14 |   Object.defineProperty(obj, name, {
     ^
TypeError: Cannot replace module namespace object's binding with configurable attribute
      at defineProperty (native:1:1)
      at defineProperty (/myproject/node_modules/.pnpm/[email protected]/node_modules/shimmer/index.js:14:10)
      at wrap (/myproject/node_modules/.pnpm/[email protected]/node_modules/shimmer/index.js:74:3)
      at /myproject/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@opentelemetry/instrumentation-http/build/src/http.js:78:13
      at /myproject/node_modules/.pnpm/@[email protected]_@[email protected]/node_modules/@opentelemetry/instrumentation/build/src/platform/node/RequireInTheMiddleSingleton.js:67:27
      at /myproject/node_modules/.pnpm/[email protected]/node_modules/require-in-the-middle/index.js:281:28
      at /myproject/node_modules/.pnpm/@[email protected]/node_modules/@smithy/node-http-handler/dist-cjs/index.js:150:3
      at anonymous (native:1:1)
      at /myproject/node_modules/.pnpm/[email protected]/node_modules/require-in-the-middle/index.js:295:32
      at /myproject/node_modules/.pnpm/@[email protected]/node_modules/@smithy/util-stream/dist-cjs/sdk-stream-mixin.js:4:1

EvHaus avatar Jul 12 '24 05:07 EvHaus

@EvHaus thanks for reaching out. I could set up a small repo and use node-file-router without any issues. Are you using any auto-instrumentation e.g. for express? Also could you provide the output when you add debug: trueto your init call? Anything that could help me reproduce your error would be helpful!

chargome avatar Jul 12 '24 07:07 chargome

Thanks for the quick response @chargome. Looks like I was missing one crucial element. Seems like it's an issue with @aws-sdk/client-s3. Simply importing from there causes the error.

The full repro is as follows:

// index.ts

import { initFileRouter } from 'node-file-router';
import { init } from '@sentry/bun';

init({dsn: '__MY_DSN__'});
await initFileRouter();
// api/index.ts

import { DeleteObjectCommand } from '@aws-sdk/client-s3';

const index = () => {
	console.log(DeleteObjectCommand);
};

export default index;

Then run the app via bun index.ts.

EvHaus avatar Jul 13 '24 04:07 EvHaus

Hello, this seems to be an issue upstream with opentelemetry and shimmer. I'm afraid there's not much we can do right now, but we're looking into that.

To get you unstuck, you could set up a manual client and drop the http integration. This way you'll at least have error tracking and basic performance data (if you use Bun.serve), but you won't get opentelemetry instrumentation, for example db integrations.

import {
  BunClient,
  defaultStackParser,
  getDefaultIntegrations,
  makeFetchTransport,
  setCurrentClient
} from '@sentry/bun'

const integrations = getDefaultIntegrations({}).filter((integration) => integration.name !== 'Http')

const client = new BunClient({
  dsn: '__MY_DSN__',
  stackParser: defaultStackParser,
  transport: makeFetchTransport,
  tracesSampleRate: 1.0,
  integrations,
})

setCurrentClient(client)
client.init()

Hope this helps!

andreiborza avatar Jul 15 '24 15:07 andreiborza

Dear @andreiborza I am currently facing the same

TypeError: Cannot replace module namespace object's binding with configurable attribute`

error. I was using @sentry/node bun after this issue, I have switched to @sentry/bun however, whenever I add the preload = ["./instrument.mjs"] in bunfig.toml I face the same error mentioned in this post. And when I remove it, it works in bun run index.mts but it does not work in production since the preload happens when we build the project. Is there any way to overcome this?

For reference: I am using Express with typescript and ESM syntax and this is the sentry debug output:

Sentry Logger [log]: Initializing Sentry: process: 73610, thread: main.
Sentry Logger [log]: Integration installed: InboundFilters
Sentry Logger [log]: Integration installed: FunctionToString
Sentry Logger [log]: Integration installed: LinkedErrors
Sentry Logger [log]: Integration installed: RequestData
Sentry Logger [log]: Integration installed: Console
Sentry Logger [log]: Integration installed: Http
Sentry Logger [log]: Integration installed: NodeFetch
Sentry Logger [log]: Integration installed: OnUncaughtException
Sentry Logger [log]: Integration installed: OnUnhandledRejection
Sentry Logger [log]: Integration installed: ContextLines
Sentry Logger [log]: Integration installed: Context
Sentry Logger [log]: Integration installed: Modules
Sentry Logger [log]: Integration installed: BunServer
Sentry Logger [log]: Running in CommonJS mode.
Sentry Logger [debug]: @opentelemetry/api: Registered a global for diag v1.9.0.
Sentry Logger [debug]: @opentelemetry/api: Registered a global for trace v1.9.0.
Sentry Logger [debug]: @opentelemetry/api: Registered a global for context v1.9.0.
Sentry Logger [debug]: @opentelemetry/api: Registered a global for propagation v1.9.0.
[Sentry] express is not instrumented. This is likely because you required/imported express before calling `Sentry.init()`.
Server is listening on port 4001

I have also realized that sentry is running in CommonJS mode. Is this normal? If not, what can I do to fix that issue too?

Thank you for your time, Tuna

Tunanika avatar Jul 31 '24 14:07 Tunanika

@Tunanika there is no need to preload the instrument file in bunfig.toml, just import the instrumentation first thing in your index file.

You will still face the issue that Sentry.setupExpressErrorHandler(app) is currently not working as expected with bun. Your express routes will however be automatically instrumented with the httpIntegration, for additional performance tracing you can make use of custom instrumentation until there is a fix available.

Regarding capturing errors you could capture exceptions using a global error handler like this:

function customErrorHandler(
  err: Error,
  _req: Request,
  res: Response,
  _next: NextFunction
) {
  Sentry.captureException(err);
  // handle your error response
  res.status(500).send("sadness...");
}

app.use(customErrorHandler);

Hope that helps you get going for now!

chargome avatar Aug 01 '24 08:08 chargome

Dear @chargome Thank you very much for your response. Yes sentry currently does capture any errors in express endpoints. However upon building the project withbun build index.mts --target bun --outdir ./out --sourcemap=externalwhen running the final index.js file with bun run index.js I face the same Cannot replace module namespace object's binding with configurable attribute issue like the following:

 9 | 
10 | // Sets a property on an object, preserving its enumerability.
11 | // This function assumes that the property is already writable.
12 | function defineProperty (obj, name, value) {
13 |   var enumerable = !!obj[name] && obj.propertyIsEnumerable(name)
14 |   Object.defineProperty(obj, name, {
     ^
TypeError: Cannot replace module namespace object's binding with configurable attribute

This is my instrument.mjs file:

import * as Sentry from "@sentry/bun";
// Ensure to call this before importing any other modules!
Sentry.init({
  dsn: "dsn",
  
  // Add Performance Monitoring by setting tracesSampleRate
  // Set tracesSampleRate to 1.0 to capture 100% of transactions
  // We recommend adjusting this value in production
  tracesSampleRate: 1.0,
});

Index.mts:

import "./instrument.mjs";
import * as Sentry from "@sentry/bun";
import express from "express";
import cors from "cors";
import morgan from "Morgan";
import cookieParser from "cookie-parser";
import type { Request, Response, NextFunction } from "express";
.
.
.
Sentry.setupExpressErrorHandler(app);

What can I do to fix the issue that it fails after building? (I have removed the preload from bunfig.toml )

Tunanika avatar Aug 01 '24 09:08 Tunanika

Hm yeah that should not be the case, we're running into the same issue again this way.. Since you're not running this code in a browser would it be an option for you to just run your server using bun run index.ts for now?

chargome avatar Aug 01 '24 11:08 chargome

Yes I can keep running the server that way it's not a problem. Thank you for your response, good to know it's not a problem with my integration.

Tunanika avatar Aug 01 '24 13:08 Tunanika

I have the same issue with graphql-yoga integration, is there a workaround?

i-void avatar Aug 05 '24 13:08 i-void

@i-void do you have a reproduction repo or a stackblitz of sorts we can look at? Otherwise, this is likely still an issue with bun and shimmer.

andreiborza avatar Aug 05 '24 14:08 andreiborza

@andreiborza not have a public repo but I think you can reproduce by installing using their docs (its simple) https://the-guild.dev/graphql/yoga-server/docs/integrations/integration-with-bun

after this just add @sentry/bun and try to init it with Sentry.init. It gives error on init. I overcome the situation by disabling Http integration and switching to @sentry/node instead of Bun. Also I had another error says startTransaction function is undefined . I fix it by changing the @sentry/node's version to same as @sentry/tracing (v7.114.0). Same error happens in @sentry/bun also and changing version didn't help.

i-void avatar Aug 05 '24 15:08 i-void

Thanks, we will take a look.

andreiborza avatar Aug 05 '24 15:08 andreiborza

Facing this same issue on v8.26.0 (@sentry/bun). Using @andreiborza's workaround in the meantime.

bephrem1 avatar Aug 20 '24 03:08 bephrem1

Hey thanks for chiming in. We're still looking into this a bit closer but are currently on limited support due to a company-wide hackweek. We'll get back to our regular support next week.

andreiborza avatar Aug 20 '24 07:08 andreiborza

@andreiborza I am experiencing the same issue in bun when I preload sentry.ts with the init config

Jonatthu avatar Aug 22 '24 08:08 Jonatthu

@Jonatthu @bephrem1 we're aware of this, there is is an open upstream issue for that: https://github.com/oven-sh/bun/issues/13165

chargome avatar Aug 26 '24 08:08 chargome

If anyone is looking for a fix that is a little closer to the standard implementation, you can do:

import * as Sentry from '@sentry/bun';

Sentry.init({
  dsn: 'YOUR_DSN',
  // TODO: Issue with standard instrumentation:
  // https://github.com/getsentry/sentry-javascript/issues/12891
  // https://github.com/oven-sh/bun/issues/13165
  defaultIntegrations: Sentry.getDefaultIntegrations({}).filter((i) => i.name !== 'Http'),
  tracesSampleRate: 1.0,
});

ian-pascoe avatar Nov 06 '24 14:11 ian-pascoe