Dev-tools - createTsProgram Error: EISDIR: illegal operation on a directory, read

I have an error in Builder DevTools. We added it to an existing Builder project (we already had many components registered in Builder) to be able to register components for Visual Editor.

npm init builder.io@latest worked fine, after adding credentials to the project we have .env file created with API key, and the Counter component was created.

But the builder-registry.ts file is empty.

Error we get in Chrome Console:

POST http://localhost:5273/~builder-dev-tools
500 Internal Server Error

Payload:
{"type":"connectBuilder","data":{"publicApiKey":"50612480d3c642cea40342a99f4dc2b7","privateAuthKey":"bpk-xxxxx"}}

Response:
{
    "errors": [
        "createTsProgram() Could not create program for: /home/lucas/DEV/lewiscellars-nextjs/builder-registry.ts"
    ]
}

I get it many times in a loop.

And in the terminal when I started the app with npm run dev I get:

POST https://cdn.builder.io/api/v2/admin, duration: 552ms
GET https://cdn.builder.io/api/v3/data?limit=1&cachebust=true&collection=content&query.published.%24ne=archived&query.query.%24elemMatch.%24and%5B0%5D.property=urlPath&query.query.%24elemMatch.%24and%5B0%5D.operator=is&query.query.%24elemMatch.%24and%5B0%5D.value=%2Fbuilder-demo&query.modelId=453dd1daf33845e89904a7c7c523e463&apiKey=50612480d3c642cea40342a99f4dc2b7, duration: 323ms
^CcreateTsProgram Error: EISDIR: illegal operation on a directory, read
    at Object.readSync (node:fs:751:3)
    at tryReadSync (node:fs:451:20)
    at readFileSync (node:fs:497:19)
    at Object.readFileSync (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node/index.cjs:1:2346)
    at Object.getSourceFile (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/core/index.cjs:22:120)
    at findSourceFileWorker (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:122233:25)
    at findSourceFile (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:122152:22)
    at /home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:122101:24
    at getSourceFileFromReferenceWorker (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:122070:28)
    at processSourceFile (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:122099:7)
    at processRootFile (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:121897:7)
    at /home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:120631:43
    at forEach (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:55:24)
    at Object.createProgram (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/node_modules/typescript/lib/typescript.js:120631:7)
    at eo (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/core/index.cjs:22:1496)
    at U (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/core/index.cjs:22:552)
    at async Xe (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/core/index.cjs:32:8332)
    at async M (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/core/index.cjs:32:8390)
    at async Do (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/core/index.cjs:230:203)
    at async dn (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/core/index.cjs:32:10267)
    at async V (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/server/index.cjs:7:3226)
    at async j (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/server/index.cjs:7:4574)
    at async X (/home/lucas/DEV/lewiscellars-nextjs/node_modules/@builder.io/dev-tools/server/index.cjs:199:985) {
  errno: -21,
  syscall: 'read',
  code: 'EISDIR'
}

And Builder DevTool’s UI told me:

Please Restart Your Dev Server
We've made updates to your application, please restart your dev server to ensure the changes take effect.

Once your dev server is restarted you'll be able to start editing your Builder content.

In Builder DevTools when I try to get into the Components tab in the right sidebar I get the same errors. I tried to add DevTools manually, without init, and got the same errors:

The Error is thrown here: /project-directory/node_modules/@builder.io/dev-tools/core/index.cjs and it’s produced by this function: e.ts.createProgram(n) (which is probably TS build-in function which is added by Builder to ts object?).

The object passed as n is just our parsed TS config file with a list of all paths (instead of include/exclude) sorted alphabetically. It looks like this:

 rootNames: [
    '/app-directory/builder-registry.ts',
    '/app-directory/cypress.config.js',
    '/app-directory/cypress.d.ts',
    '/app-directory/globals.d.ts',
...
]

If I delete builder-registry.ts file (which is the first element in rootNames) I just get exactly the same error for the next file which is passed to Webpack in rootNames. If I delete that file, I get the same error for the next file from the list, and so on, probably for all files in our Project.

The order of paths is exactly the same as the order of errors I get when deleting files from our project (to validate if deleting the file will fix the error).

I tried it in another project, and it worked fine, I had Counter registered in builder-registry.ts file and I get also different info in DevTools UI with a list of changed files. So probably something is wrong with the configuration of our project. But after many hours I’m still not able to fix it… :frowning:

Some hypothesis I validated:

  • write/read permissions to files and directories
  • wrong paths in our next/ts configs
  • wrong include/exclude setting in tsconfig.json
  • Builder DevTools creates .env file with NEXT_PUBLIC_BUILDER_API_KEY for the env we Selected in Builder when authorizing the plugin, but we use .envrc file. But I make sure we have the same Env and it didn’t fixed anythig. BTW, Dev Tools will not work without .env file? (if I delete it it shows me configuration page again). So we need both .env and our .envrc?
  • deleting the files which are “causing” errors (as mentioned before, I just get the same “createTsProgram() Could not create program” error for the next file from rootNames, which is an alphabetical list of all files in our project).
  • deleting .next and node_moedules folders and installing/building again.
  • cloning a new repo with our project in different place on my laptop and also on other laptop.
  • validating on MacOS (the other person from my team has the same errors I have on Ubuntu)

Builder public api key
50612480d3c642cea40342a99f4dc2b7

Screenshots or video link

Code stack you are integrating Builder with

"dependencies": {
    "@builder.io/dev-tools": "^1.0.1",
    "@builder.io/react": "^3.2.6",
    "@builder.io/sdk": "^2.2.2",
    "@builder.io/utils": "^1.1.19",
    "@floating-ui/react-dom": "^1.0.0",
    "@n8tb1t/use-scroll-position": "^2.0.3",
    "@sentry/nextjs": "^7.92.0",
    "@svgr/webpack": "^8.0.1",
    "@tanstack/react-query": "^4.35.3",
    "@tanstack/react-query-devtools": "^4.35.3",
    "@wonderful/wine-components": "^0.37.3",
    "@wonderful/wwc": "^3.37.0",
    "body-scroll-lock": "^3.1.5",
    "dayjs": "^1.11.10",
    "fromentries": "^1.3.2",
    "isomorphic-dompurify": "^1.2.0",
    "js-cookie": "^3.0.5",
    "jwt-decode": "^3.1.2",
    "next": "^12.3.4",
    "next-seo": "^6.0.0",
    "nextjs-cors": "^2.1.1",
    "nextjs-progressbar": "^0.0.16",
    "query-string": "^7.1.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-focus-lock": "^2.9.6",
    "react-hook-form": "^7.49.3",
    "react-to-print": "^2.14.7",
    "sass": "^1.69.7",
    "sharp": "^0.33.1",
    "swiper": "^9.3.2"
  },
  "devDependencies": {
    "@babel/core": "^7.23.7",
    "@next/bundle-analyzer": "^12.2.4",
    "@testing-library/cypress": "^10.0.1",
    "@types/body-scroll-lock": "^3.1.0",
    "@types/js-cookie": "^3.0.6",
    "@types/node": "^18.11.9",
    "@types/react": "^17.0.74",
    "@types/vimeo__player": "^2.16.3",
    "@types/webpack-env": "^1.17.0",
    "@typescript-eslint/eslint-plugin": "^5.32.0",
    "babel-loader": "^8.2.5",
    "babel-plugin-istanbul": "^6.1.1",
    "cypress": "^13.3.2",
    "cypress-localstorage-commands": "^2.2.4",
    "eslint": "^8.21.0",
    "eslint-config-next": "^12.2.4",
    "eslint-config-prettier": "^8.5.0",
    "eslint-plugin-import": "^2.27.5",
    "next-sitemap": "^4.2.3",
    "node-fetch": "^3.3.2",
    "prettier": "^2.8.7",
    "typescript": "^4.9.5",
    "util": "^0.12.5"
  }

I tried also to change ts exclude/include but it didn’t help:

  "include": [
    "cypress.d.ts",
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx",
    "next-sitemap.config.mjs"
  ],
  "exclude": [
    "node_modules",
    "**/node_modules",
    "storybook",
    "cypress",
    "cypress.config.js",
    "**/*.ts/**",
    "**/*.tsx/**"
  ]

This is our current next.config.js

/* eslint-disable @typescript-eslint/no-var-requires */
const path = require('path');
const withBuilderDevTools = require('@builder.io/dev-tools/next')();
const { withSentryConfig } = require('@sentry/nextjs');
const withBundleAnalyzer = require('@next/bundle-analyzer')({
  enabled: process.env.ANALYZE === 'true',
});
const { REDIRECTS } = require('./config/redirects.json');
const moduleExports = withBundleAnalyzer({
  experimental: { esmExternals: true },
  webpack(config, { webpack, isServer }) {
    config.module.rules.push({
      test: /\.svg$/,
      use: ['@svgr/webpack'],
    });
    const isProdEnv = process.env.NEXT_PUBLIC_ENVIRONMENT === 'production';
    // https://docs.sentry.io/platforms/javascript/guides/nextjs/configuration/tree-shaking/
    config.plugins.push(
      new webpack.DefinePlugin({
        __SENTRY_DEBUG__: isProdEnv ? false : true,
        __SENTRY_TRACING__: isProdEnv ? false : true,
      })
    );
    // only applies for `npm run dev`
    if (process.NODE_ENV !== 'production') {
      // When developing with symlink to a local @wonderful/wwc we get "can't resolve XYZ" errors (e.g. "can't resolve Canvas" error from jsdom).
      // Below packages are not required by our dependencies (optional dep) so we can ignore them locally:
      config.plugins.push(
        new webpack.IgnorePlugin({
          resourceRegExp: /canvas/,
          contextRegExp: /jsdom$/,
        }),
        new webpack.IgnorePlugin({
          resourceRegExp: /bufferutil/,
          contextRegExp: /ws\/lib$/,
        }),
        new webpack.IgnorePlugin({
          resourceRegExp: /utf-8-validate/,
          contextRegExp: /ws\/lib$/,
        })
      );
    }
    // Fix issues with react-query:
    // https://github.com/TanStack/query/issues/3595
    config.resolve.alias['@tanstack/react-query'] = path.resolve(
      './node_modules/@tanstack/react-query'
    );
    if (isServer) {
      config.externals = ['@tanstack/react-query', ...config.externals];
    }
    return config;
  },
  sassOptions: {
    includePaths: [path.join(__dirname, 'styles')],
  },
  i18n: {
    locales: ['en'],
    defaultLocale: 'en', // this adds lang="en" to <html>
  },
  sentry: {
    hideSourceMaps:
      process.env.NEXT_PUBLIC_ENVIRONMENT === 'production' ? true : false,
  },
  images: {
    domains: ['images.commerce7.com', 'cdn.builder.io'],
  },
  // If we want source maps provided with Sentry Errors we need this option enabled. But it will make production builds longer.
  // More about this option:
  // - https://nextjs.org/blog/next-11-1#source-maps
  // - https://nextjs.org/docs/advanced-features/source-maps
  productionBrowserSourceMaps: true,
  swcMinify: true, // 7 times faster minification.
  async redirects() {
    return REDIRECTS;
  },
  poweredByHeader: false,
});
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 in terminal
  debug: false,
  // For all available options, see:
  // https://github.com/getsentry/sentry-webpack-plugin#options.
};

module.exports = withBuilderDevTools(
  withSentryConfig(moduleExports, sentryWebpackPluginOptions)
);

BTW, other questions we have:

  1. is it possible to use builder-registry.tsx (instead of ts)? Now it doesn’t work when I just change the extension. We use some JSX in some of our register functions, our setup is quite complicated).
  2. Is it possible to make DevTools see our external UI components? For now I see that only components that are created directly in the code are seen by DevTools. Our UI components from common UI library are registered by us manually but DevTools don’t see them… So we can’t map them to our Figma components :frowning: 90% of our components are in UI libraries…

You may find help at

  1. Ideally it should work, though you may need to import builder-registry.tsx file in the component → builder.tsx file for app router or _app.tsx for pages router.

  2. You can try importing external component in the builder-registry.tsx file and see if that works.

Hey, thanks for response.

I’m afraid it’s not the same case. We get this error from the same function (createTsProgram) but the error is totally different (illegal operation on a directory, read vs Invalid path). We don’t have a Monorepo with local packages, and we get the same error for every file in our project (not only for a specific file).

Please, can you analyze what can cause this error in your code?
Where e.ts.createProgram(n) function comes from? Is it TS function? What is it’s original name? I try to find what directory it may try to read, but without success so far.

Is it possible to see somewhere the source code of your DevTools? (I don’t see in on your Github and it’s hard to debug it with minified version)

  1. Ideally it should work, though you may need to import builder-registry.tsx file in the component → builder.tsx file for app router or _app.tsx for pages router.
  2. You can try importing external component in the builder-registry.tsx file and see if that works.

Thanks, we tried both, and it doesn’t work.

  1. we can use whatever name we want instead of builder-registry.ts (initially we had /components/builder/index.tsx) and it will work for Builder.io when we will import this file in our _app.tsx file = we have access to these components in Builder UI. But it doesn’t work for DevTools - it seems you expect the exact file name and location (but without access to DevTool’s source code I can’t validate it).
    It would be great to have a config option as an argument to your devtools initialization function to provide any path and name for “registry” file we want (we would just point to our current /components/builder/index.tsx without refactoring our code).

  2. I’ve moved all our imports of external components from /components/builder/index/tsx file to builder-registry.ts file, they are registered in Builder.io UI, but DevTools just don’t see them (in right sidebar > Components tab). It looks like it expects the files with components definition / export in project’s directory. Any other suggestions please?

Hello @LucasMatuszewski,

At present, modifying the builder-registry.ts file isn’t possible. However, if you believe this functionality should be allowed, we recommend submitting a feature request at our Ideas Portal.