Skip to content

Injected debug id causing hash differences in cross-architecture builds #15745

Closed
getsentry/sentry-javascript-bundler-plugins
#702

Description

@Redmega

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which SDK are you using?

@sentry/nextjs

SDK Version

^9.5.0

Framework Version

next ^14.2.24

Link to Sentry event

No response

Reproduction Example/SDK Setup

No response

Steps to Reproduce

  1. Use [contenthash] in place of [chunkhash] for consistent cross-architecture builds
  2. Build docker image for multiple architectures
  3. Note that each build has generated a different debugId, which causes the contenthash to change.

Expected Result

Content hashes should be consistent across architectures. I think we can accomplish this by specifying which hash the debugId uses, I suspect it's using the id/chunkhash and not the contenthash?

Actual Result

Content hashes are different across architectures. Similar to the issue described in #13971

Activity

  1. added theissue type on Mar 19, 2025
  2. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Mar 19, 2025
  3. changed the title [-]Injected debug script causing hash differences in cross-architecture builds[/-] [+]Injected debug id causing hash differences in cross-architecture builds[/+] on Mar 19, 2025
  4. andreiborza commented on Mar 20, 2025

    @andreiborza
    Member

    Hi @Redmega, thanks for filing this.

    Afaik, debug ids are generated based on code, hashes are stripped from the file endings. Are you observing consistent hashes without Sentry?

    cc @lforst

  5. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Mar 20, 2025
  6. lforst commented on Mar 20, 2025

    @lforst
    Contributor

    What are you using to inject debug IDs? The CLI? If so, it should inject a deterministic uuid based on file-content.

  7. Redmega commented on Mar 20, 2025

    @Redmega
    Author

    What are you using to inject debug IDs? The CLI? If so, it should inject a deterministic uuid based on file-content.

    Sorry, not sure why I had @sentry/browser in the opening comment, I'm using @sentry/nextjs. I must have overlooked that.

    We also use nx and this is how my config ends up looking with plugin composition:

      nxComposePlugins(withNx, withBundleAnalyzer, (config) => withSentryConfig(config, sentryConfig))(nextConfig);

    Afaik, debug ids are generated based on code, hashes are stripped from the file endings. Are you observing consistent hashes without Sentry?

    Yes, hashes are consistent between architectures when not using the sentry plugin (caveat: I replace [chunkhash] with [contenthash] as the arm/amd builds were generating different chunkhashes):

    ARM (No Sentry)

    ├ chunks/framework-6d28727e634f0245.js   44.9 kB
    ├ chunks/main-3455d129e2595baf.js        32.3 kB
    ├ chunks/pages/_app-7c7a48c21a77f379.js  824 kB
    ├ css/ac0fbf6c8e1d87bd.css               36.1 kB
    

    AMD (No Sentry)

    ├ chunks/framework-6d28727e634f0245.js   44.9 kB
    ├ chunks/main-3455d129e2595baf.js        32.3 kB
    ├ chunks/pages/_app-7c7a48c21a77f379.js  824 kB
    ├ css/ac0fbf6c8e1d87bd.css               36.1 kB
    

    I also went into the differently hashed files (in this case it was only _app-*.js) and confirmed that when the sentry debug injected code was removed, the files hashed identically and had no diff.

    ARM (Sentry)

    ├ chunks/pages/_app-40949006ebec3ca7.js  865 kB
    

    AMD (Sentry)

    ├ chunks/pages/_app-bc03ec9e4895a4b6.js  865 kB
    

    Looking at the logs, I suspect that sentry is injecting the code before nextjs has calculated the hashes and output the files, so when nextjs calculates the contenthash they are different. As to why the uuid is different between the two architectures for the same file contents, I'm not sure. I need to dig into the intermediary steps more.

  8. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Mar 20, 2025
  9. Redmega commented on Mar 20, 2025

    @Redmega
    Author

    Actually, in the webpack plugin which is what the nextjs plugin uses under the hood I believe? hash is used instead of contenthash.

    const debugId = arg?.chunk?.hash ? stringToUUID(arg.chunk.hash) : uuidv4();

    It's my understanding that hash is generated per-build so because we have to build on each architecture, we have two builds, and therefore two hashes. Either that or the hash differs because of the architecture itself. I think this explains why the uuid differs between the two architectures, and a possible fix is to use contenthash and not hash from the chunk.

  10. Redmega commented on Mar 20, 2025

    @Redmega
    Author

    As a workaround I wrote a plugin to patch the BannerPlugin added by sentry to look at contentHash instead of hash. Now my build artifacts match across architectures.

    class SentryDebugIdPatchPlugin {
      wrapBanner(bannerPlugin) {
        bannerPlugin.banner = (arg) => {
          if (arg?.chunk?.contentHash?.javascript) {
            return bannerPlugin.options.banner({ chunk: { hash: arg.chunk.contentHash.javascript } });
          }
          return bannerPlugin.options.banner(arg);
        };
      }
    
      apply(compiler) {
        const bannerPlugin = compiler.options.plugins.find(
          (p) => p.constructor.name === "BannerPlugin" && p.banner?.toString().includes("getDebugIdSnippet"),
        );
        this.wrapBanner(bannerPlugin);
      }
    }

    I think an option to use the content hash instead of the chunk hash would be ideal for usecases like this.

  11. andreiborza commented on Mar 21, 2025

    @andreiborza
    Member

    Ah, great find. Making this configurable for webpack sounds reasonable to me, wdyt @lforst?

  12. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Mar 21, 2025
  13. lforst commented on Mar 21, 2025

    @lforst
    Contributor

    @andreiborza I don't think an option is necessary. I don't think hash is different for every build, but we can just default to contentHash and fall back to hash.

  14. Redmega commented on Mar 21, 2025

    @Redmega
    Author

    You're right actually, I just tested without the sentry plugin at all (and reverting my contenthash to chunkhash) and the file hashes are identical. So something else might be going on here...

  15. moved this to Waiting for: Product Owner in GitHub Issues with 👀 3on Mar 21, 2025
  16. Redmega commented on Mar 21, 2025

    @Redmega
    Author

    Good callout @lforst thanks. I looked deeper at the build logs and tried different configurations. With sentry plugin added, it seems like the chunk hash can differ between the builds when they are processed in a different order. No idea why this doesn't occur when the sentry plugin is removed.

    AMD

    static/chunks/pages/_error-daeeb4e5722987a3.js; id: 820; chunk hash: 2754d7b320645753; content hash: daeeb4e5722987a3;
    static/chunks/pages/_app-2c53b49aedbaa32e.js; id: 888; chunk hash: f0d94ef992a50815; content hash: 2c53b49aedbaa32e;
    

    ARM

    static/chunks/pages/_app-2c53b49aedbaa32e.js; id: 888; chunk hash: 092359f98c23be17; content hash: 2c53b49aedbaa32e;
    static/chunks/pages/_error-daeeb4e5722987a3.js; id: 820; chunk hash: 2754d7b320645753; content hash: daeeb4e5722987a3;
    

    Note the content hashes are identical, and even the id's are identical, but the chunk hashes are different, but only for this _app file. The chunk hash of the other file whose processing order changed (_error) is the same. I'm kinda stumped here. Looking at the files, they are identical and the only difference ends up being the injected sentryDebugId.

    Nevertheless, using contenthash instead of chunkhash does seem to resolve all my issues. So... 🤷

  17. lforst commented on Mar 24, 2025

    @lforst
    Contributor

    Thanks for the followup! We'll just default to contentHash and use chunk.hash if that's not available.

  18. moved this from Waiting for: Product Owner to No status in GitHub Issues with 👀 3on Mar 24, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions