Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TypeError: withSentryConfig is not a function #5511

Closed
3 tasks done
coreypett33 opened this issue Aug 2, 2022 · 24 comments · Fixed by #8166
Closed
3 tasks done

TypeError: withSentryConfig is not a function #5511

coreypett33 opened this issue Aug 2, 2022 · 24 comments · Fixed by #8166

Comments

@coreypett33
Copy link

Is there an existing issue for this?

How do you use Sentry?

Sentry Saas (sentry.io)

Which package are you using?

@sentry/nextjs

SDK Version

7.8.1

Framework Version

"react": "^17.0.2", "next": "^11.1.2",

Link to Sentry event

No response

Steps to Reproduce

  1. add sentry to nextjs application.
    https://docs.sentry.io/platforms/javascript/guides/nextjs/
  2. update next.config.js
// This file sets a custom webpack configuration to use your Next.js app
// with Sentry.
// https://nextjs.org/docs/api-reference/next.config.js/introduction
// https://docs.sentry.io/platforms/javascript/guides/nextjs/

const { withSentryConfig } = require('@sentry/nextjs');

const moduleExports = {
  // Your existing module.exports
  reactStrictMode: true,
  swcMinify: true,
};

const sentryWebpackPluginOptions = {
  // Additional config options for the Sentry Webpack plugin. Keep in mind that
  // the following options are set automatically, and overriding them is not
  // recommended:
  //   release, url, org, project, authToken, configFile, stripPrefix,
  //   urlPrefix, include, ignore

  silent: true, // Suppresses all logs
  // For all available options, see:
  // https://github.com/getsentry/sentry-webpack-plugin#options.
};

// Make sure adding Sentry options is the last code to run before exporting, to
// ensure that your source maps include changes from all other Webpack plugins
module.exports = withSentryConfig(moduleExports, sentryWebpackPluginOptions);

  1. run yarn dev

Expected Result

App should start

Actual Result

localhost:3001 shows the following error in chrome.
Screen Shot 2022-08-02 at 5 40 42 AM

Terminal does not show the error.

Screen Shot 2022-08-02 at 5 52 03 AM

@lobsterkatie
Copy link
Member

Hi, @coreypett33.

I've tried and can't replicate this behavior. Can you please provide a small repro app?

@github-actions
Copy link
Contributor

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@bramski
Copy link

bramski commented Oct 25, 2022

I immediately hit this error using the sentry wizard. Something is broken with it.

@BARK-RMILLER
Copy link

BARK-RMILLER commented Oct 31, 2022

For future people who encounter this error: I fixed this by converting my next.config.js file into next.config.mjs. This allowed me to do the sentry import like so: const { withSentryConfig } = await import('@sentry/nextjs');

Then export the config like so: export default withSentryConfig(nextConfig, sentryWebpackPluginOptions);

The issue seems to be that the Sentry configuration requires that you do a module import, which isn't supported by a regular next.config.js. See the next.js docs on the config file here.

@Geczy
Copy link

Geczy commented Jan 20, 2023

const { withSentryConfig } = await import('@sentry/nextjs');

this didnt fix the issue for me

@prateekjain98
Copy link

I'm trying to upgrade from 7.30.0 to 7.43.0 but when I try to upgrade, it throws this error while building.

@lforst
Copy link
Member

lforst commented Mar 29, 2023

We need reproduction in order to fix this.

@amitav13
Copy link

@prateekjain98 and I managed to fix this by deleting our yarn.lock and installing dependencies again. Not sure what exactly fixed it, but my guess is that there was a mix of dependencies installed through yarn install and npm install that caused dependency issues.

@luhmann
Copy link

luhmann commented Apr 5, 2023

@lforst Reproduction here: https://github.com/luhmann/nextjs-with-sentry-not-function-repro

The underlying problem seems to be that new versions withSentryConfig do not seem to support using the function-style of exporting a nextjs-config ref. This worked for me up until version 7.31.1 and is needed in order to make the config dynamic based on nextjs phases.

This is what I did to get to the code in the repo linked above:

npx create-next-app demo
# choose all defaults
npm i @sentry/nextjs
npx @sentry/wizard
# complete
# merge next config js
# Switch to nextjs config-file-style where you return the config as result of a function
next build

If there is a new way required to get this capability please point me to the required documentation. I checked the manual setup docs and could not find anything.

My full next.config.js that worked as intended till v7.31.1 of @sentry/nextjs if it is helpful:

const { withSentryConfig } = require("@sentry/nextjs");
const { PHASE_DEVELOPMENT_SERVER } = require("next/constants");

const ContentSecurityPolicy = `
  default-src 'self';
  base-uri 'self';
  connect-src 'self' https:;
  font-src 'self' https: data:;
  form-action 'self';
  frame-ancestors 'none';
  img-src 'self' https: data:;
  object-src 'none';
  script-src 'self';
  script-src-attr 'none';
  style-src 'self' https: 'unsafe-inline';
  upgrade-insecure-requests;
`;
const defaultSecurityHeaders = [
  {
    key: "X-DNS-Prefetch-Control",
    value: "on",
  },
];

const productionSecurityHeaders = [
  {
    key: "Strict-Transport-Security",
    value: "max-age=63072000; includeSubDomains; preload",
  },
];

/**
 * @type {import('next').NextConfig}
 */
const config = {
  // * enable strict mode, prevents errors that might make further migrations to React Server Components harder
  reactStrictMode: true,

  // * remove powered-by header as requested by GSO
  poweredByHeader: false,

  // * enable source maps for production builds, this is needed by sentry
  productionBrowserSourceMaps: true,

  images: {
    disableStaticImages: true,
  },

  compiler: {
    // * removes console.log statements from production builds, all logging should be done in sentry for prod
    removeConsole: true,
  },

  // * needed for setting the `lang`-attribute on the html-tag
  i18n: {
    locales: ["en"],
    defaultLocale: "en",
  },

  // * Activates output-file tracing to enable deploys that do not need to install `node_modules`
  // * @see https://nextjs.org/docs/advanced-features/output-file-tracing
  output: "standalone",

  webpack(config, { webpack }) {
    // * enables you to do `import SvgIcon from './svg-file.svg'`
    config.module.rules.push({
      test: /\.svg$/,
      issuer: { and: [/\.(js|ts|md)x?$/] },
      use: ["@svgr/webpack"],
    });

    // * Make sure test-files and mock files do not accidentally end up in production bundles
    config.plugins.push(
      new webpack.IgnorePlugin({ resourceRegExp: /test\.tsx$|test\.ts$/ }),
      new webpack.IgnorePlugin({ resourceRegExp: /.+/, contextRegExp: /mocks/ })
    );

    return config;
  },
};

module.exports = (phase, defaults) => {
  if (phase === PHASE_DEVELOPMENT_SERVER) {
    return {
      ...config,
      async headers() {
        return [
          {
            // all routes
            source: "/:path*",
            headers: defaultSecurityHeaders,
          },
        ];
      },
    };
  }

  // * disable production security header in tests, otherwise the browser will try to upgrade
  // * all requests to https
  if (process.env.NODE_ENV === "test") {
    return {
      ...config,
      async headers() {
        return [
          {
            // all routes
            source: "/:path*",
            headers: defaultSecurityHeaders,
          },
        ];
      },
    };
  }

  const sentryConfig = {
    ...config,
    sentry: {
      hideSourceMaps: true,

      disableServerWebpackPlugin: true,
      disableClientWebpackPlugin: true,
    },
    async headers() {
      return [
        {
          // all routes
          source: "/:path*",
          headers: [...defaultSecurityHeaders, ...productionSecurityHeaders],
        },
      ];
    },
  };

  return withSentryConfig(sentryConfig)(phase, defaults);
};

@lforst
Copy link
Member

lforst commented Apr 5, 2023

@luhmann withSentryConfig returns whatever you pass in as first argument. If you pass in an object, it will return an object. If you pass in a function, it will return a function.

In your repro you pass in an object, and try to call the return value. This will fail since you cannot call an object.

Also I think your error is slightly different than what was reported in this issue so we still lack repro.

@luhmann
Copy link

luhmann commented Apr 5, 2023

@lforst Thank you for your help, this indeed solved the problem. And you are correct this is a different problem, got a bit lost in the Github issues. Sorry about that.

In your repro you pass in an object, and try to call the return value. This will fail since you cannot call an object.

The interface of withSentryConfig seems to have changed with this commit. Before that it always returned a function. To me this was surprising as at least under semver (which you might not follow in this package, don't actually know) it would constitute a breaking change. It would be great if something like this could be mentioned in the CHANGELOG in the future, but I guess, I could have done some digging on my own.

Thank you again for your speedy reply.

@lforst
Copy link
Member

lforst commented Apr 5, 2023

@luhmann no worries! The changes around withSentryConfig we're indeed not the cleanest. That's on me. In the future, I recommend checking the type definitions signatures though because technically withSentryConfig can return both a function and an object and your implementations should need to handle both in case you depend on its return value. And that type definition has never changed.

@Rizki36
Copy link

Rizki36 commented Apr 18, 2023

Everything is running fine, but on a certain page, I imported Next.js config (import config from 'next.config'), then an error occurred: TypeError: withSentryConfig is not a function.

@lforst
Copy link
Member

lforst commented Apr 18, 2023

@Rizki36 Importing withConfig from a page is not a supported use-case. Why are you doing that?

@github-actions
Copy link
Contributor

This issue has gone three weeks without activity. In another week, I will close it.

But! If you comment or otherwise update it, I will reset the clock, and if you label it Status: Backlog or Status: In Progress, I will leave it alone ... forever!


"A weed is but an unloved flower." ― Ella Wheeler Wilcox 🥀

@ianbayne
Copy link

@lforst, I'm getting the same error ("TypeError: withSentryConfig is not a function") after using the wizard. Admittedly, I'm a webpack and NextJS newbie, but nothing stands out as being obviously wrong and I've double-checked with the docs https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/#extend-your-nextjs-configuration.

My next.config.js file is as follows. I'd greatly appreciate any help you can give 🙇

const path = require('path');
const { withSentryConfig } = require('@sentry/nextjs');

const { i18n } = require('./next-i18next.config');

module.exports = {
  swcMinify: true,
  experimental: {
    outputStandalone: true,
  },
  trailingSlash: true,
  reactStrictMode: true,
  env: {
    API_KEY: process.env.API_KEY,
  },
  webpack: (config) => {
    config.resolve.fallback = { fs: false, os: false };

    return config;
  },
  webpackDevMiddleware: (config) => {
    config.watchOptions = {
      poll: 1000,
      aggregateTimeout: 300,
    };
    return config;
  },
  sassOptions: {
    includePaths: [path.join(__dirname, 'styles')],
    prependData: `@import "src/styles/mixins/mixins.scss";`,
  },
  eslint: {
    dirs: ['src'],
  },
  images: {
    deviceSizes: [640, 750, 828, 1080, 1200, 1920],
    domains: [
      <redacted>
    ],
  },
  i18n,
  async headers() {
    return [
      {
        source: '/(.*)',
        headers: [
          {
            key: 'Content-Security-Policy',
            value: 'frame-ancestors <redacted>;',
          },
          {
            key: 'X-Frame-Options',
            value: 'ALLOW-FROM <redacted>;',
          },
          {
            key: 'Strict-Transport-Security',
            value: 'max-age=31536000;',
          },
        ],
      },
    ];
  },
};

module.exports = withSentryConfig(
  module.exports,
  {
    // For all available options, see:
    // https://github.com/getsentry/sentry-webpack-plugin#options

    // Suppresses source map uploading logs during build
    silent: true,

    org: <redacted>,
    project: <redacted>,
  },
  {
    // For all available options, see:
    // https://docs.sentry.io/platforms/javascript/guides/nextjs/manual-setup/

    // Upload a larger set of source maps for prettier stack traces (increases build time)
    widenClientFileUpload: true,

    // Transpiles SDK to be compatible with IE11 (increases bundle size)
    transpileClientSDK: true,

    // Routes browser requests to Sentry through a Next.js rewrite to circumvent ad-blockers (increases server load)
    tunnelRoute: '/monitoring',

    // Hides source maps from generated client bundles
    hideSourceMaps: true,

    // Automatically tree-shake Sentry logger statements to reduce bundle size
    disableLogger: true,
  }
);

@lforst
Copy link
Member

lforst commented May 15, 2023

@ianbayne What version of the Next.js SDK are you on?

@ianbayne
Copy link

Thanks for the speedy response, @lforst! Here are the relevant dependency versions from my package.json:

"@sentry/nextjs": "^7.51.2",
"next": "^12.1.6",

Please let me know if there's any other information you need.

@lforst
Copy link
Member

lforst commented May 15, 2023

@ianbayne can you try wiping your node_modules and reinstalling them? Thanks.

@ianbayne
Copy link

Thanks, @lforst.

Unfortunately even after doing so I still get the same error. Interestingly I notice my local Next server is showing a different error than the browser:

wait  - compiling...
error - (middleware)/src/pages/_middleware.ts (17:0) @ <unknown>
TypeError: Cannot read properties of undefined (reading 'getInitialProps')
  15 | const pageComponent = userPageModule.default;
  16 | 
> 17 | const origGetInitialProps = pageComponent.getInitialProps;
  18 | const origGetStaticProps = userPageModule.getStaticProps;
  19 | const origGetServerSideProps = userPageModule.getServerSideProps;

The content of my _middleware.ts file is:

import { NextRequest, NextResponse } from 'next/server';

// Regex to check whether something has an extension, e.g. .jpg
const PUBLIC_FILE = /\.(.*)$/;

const countries = ['en-US', 'fr', 'de', 'it'];

// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
export const middleware = (request: NextRequest) => {
  const { nextUrl, headers } = request;
  const url = nextUrl.clone();

  const language =
    headers
      .get('accept-language')
      ?.split(',')?.[0]
      .split('-')?.[0]
      .toLowerCase() || 'en-US';

  try {
    // Early return if it is a public file such as an image
    if (PUBLIC_FILE.test(nextUrl.pathname)) {
      return undefined;
    }
    // Early return if this is an api route
    if (nextUrl.pathname.includes('/api')) {
      return undefined;
    }

    if (nextUrl.pathname === '/' && nextUrl.locale === '__default') {
      url.pathname = countries.includes(language) ? `/${language}` : `/en-US`;
      return NextResponse.redirect(url);
    }

    // If everything else falls through continue on with response as normal
    return undefined;
  } catch (error) {
    console.log(error);
  }
};

and the file where getInitialProps() is used:

// src/pages/_document.tsx

import Document, {
  Html,
  Head,
  Main,
  NextScript,
  DocumentContext,
  DocumentInitialProps,
} from 'next/document';

class MyDocument extends Document {
  static async getInitialProps(
    ctx: DocumentContext
  ): Promise<DocumentInitialProps> {
    const initialProps = await Document.getInitialProps(ctx);

    return initialProps;
  }

  render(): JSX.Element {
    return (
      <Html>
        <Head />
        <body>
          <Main />
          <NextScript />
        </body>
      </Html>
    );
  }
}

export default MyDocument;

I've looked through the Sentry GitHub issues on getInitialProps() but don't see anything applicable...

@lforst
Copy link
Member

lforst commented May 16, 2023

@ianbayne Can you try migrating your _middleware.ts from the legacy version ("_middleware") to the current version ("middleware.ts") - https://nextjs.org/docs/pages/building-your-application/routing/middleware#convention

@ianbayne
Copy link

Thanks for the response, @lforst. I was actually able to resolve the issue I was having by doing both of the following:

  1. We had a component file that was importing the Next config in order to get access to the i18n object / locales. Instead of doing that, I used Next's useRouter() hook to access locales as shown in Next's docs here. I'm assuming the Next config should never be imported into another file; is this correct?
  2. Updating the Sentry section of my Next config to have autoInstrumentServerFunctions set to false. It seems with it set to true you can't have named exports from the middleware file. (Alternatively, I could of course have changed the middleware file to have a default export.) I discovered this from issue @sentry/next.js 7.31 autoinstrumentation breaks middleware with named export #6815.

Thanks again for all your help!

@lforst
Copy link
Member

lforst commented May 18, 2023

@ianbayne Thanks for giving an update! We didn't consider that people may import the next config from components. I think this is something we should fix (by exporting the function on the clientside but making it a noop).

As for the middleware. I actually wanna discourage you from setting autoInstrumentServerFunctions to false, this will disable a huge chunk of features in the SDK unless you wrap everything manually. It should honestly be enough if you rename/move src/pages/_middleware.ts to src/middleware.ts. If that won't work with autoInstrumentServerFunctions: true we have something to fix. You're currently using an outdated way of defining middleware which we don't support: https://nextjs.org/docs/messages/middleware-upgrade-guide#how-to-upgrade

@ianbayne
Copy link

Thanks, @lforst.

Despite the error message above, my middleware file is indeed located at src/middleware.ts, not src/pages/_middleware.ts. Additionally, the file name is not prefixed with an underscore (I must have gotten confused above by the error message).

What's more, removing autoInstrumentServerFunctions: false does not seem to impact the functioning of our app. I must have been mistaken about that.

Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.