prisma: `Uncaught TypeError: Error resolving module specifier “.prisma/client/index-browser”. Relative module specifiers must start with “./”, “../” or “/”.`

Bug description

I have the following error message in my browser upon using sveltekit and the command “npm run preview”:

Uncaught TypeError: Error resolving module specifier “.prisma/client/index-browser”. Relative module specifiers must start with “./”, “../” or “/”.

It references a piece of code that was compiled with “npm run build” in localhost:3000/_app/start-b07b1607.js:

...s-d1fb5791.js";import".prisma/client/index-browser";let Be="",et="";function ...

How to reproduce

I have tried reproducing this error with using older versions of Prisma, the adaptor and Svelte, switching from pnpm to npm, but nothing helps. I have a MWE repository that comes close to reproducing the error but doesn’t actually reproduce it at https://github.com/wvhulle/prisma-sveltekit-bug-report.

Expected behavior

How come the Svelte compiler emits “.prisma/client/index-browser” as a module specifier? Is this an error in Prisma, Vite or something else? The dev mode works without problem.

The question seems to be related, but is about Vue, not about Svelte.

Prisma information

I cannot share the schema, but this is the query that happens on the page where the error happens.

import prisma from '$lib/db';

export async function get() {
    const projects = await prisma.project.findMany({})
    return { body: projects }
}

And i am using this solution for the production build of Sveltekit:

import pkg, { PrismaClient } from '@prisma/client';
import { dev } from '$app/env';

declare global {
    var _prisma: PrismaClient; // eslint-disable-line
}

let prisma;
if (dev) {
    if (!global._prisma) {
        global._prisma = new PrismaClient();
    }
    prisma = global._prisma;
} else {
    const { PrismaClient: PrismaClientProd } = pkg;
    prisma = new PrismaClientProd();
}

export default prisma as PrismaClient; // type assertion for shim

Environment & setup

  • OS: Linux Mint 20.3
  • Database: PostgreSQL
  • Node.js version: v17.8.0

Prisma Version

prisma                  : 3.11.0
@prisma/client          : 3.11.0
Current platform        : debian-openssl-1.1.x
Query Engine (Node-API) : libquery-engine b371888aaf8f51357c7457d836b86d12da91658b (at ../../../../.pnpm-store/v3/tmp/_npx/69216/5/node_modules/.pnpm/@prisma+engines@3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b/node_modules/@prisma/engines/libquery_engine-debian-openssl-1.1.x.so.node)
Migration Engine        : migration-engine-cli b371888aaf8f51357c7457d836b86d12da91658b (at ../../../../.pnpm-store/v3/tmp/_npx/69216/5/node_modules/.pnpm/@prisma+engines@3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b/node_modules/@prisma/engines/migration-engine-debian-openssl-1.1.x)
Introspection Engine    : introspection-core b371888aaf8f51357c7457d836b86d12da91658b (at ../../../../.pnpm-store/v3/tmp/_npx/69216/5/node_modules/.pnpm/@prisma+engines@3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b/node_modules/@prisma/engines/introspection-engine-debian-openssl-1.1.x)
Format Binary           : prisma-fmt b371888aaf8f51357c7457d836b86d12da91658b (at ../../../../.pnpm-store/v3/tmp/_npx/69216/5/node_modules/.pnpm/@prisma+engines@3.11.0-48.b371888aaf8f51357c7457d836b86d12da91658b/node_modules/@prisma/engines/prisma-fmt-debian-openssl-1.1.x)
Default Engines Hash    : b371888aaf8f51357c7457d836b86d12da91658b
Studio                  : 0.458.0
Preview Features        : fullTextSearch

About this issue

  • Original URL
  • State: open
  • Created 2 years ago
  • Reactions: 20
  • Comments: 70 (12 by maintainers)

Commits related to this issue

Most upvoted comments

i got a solution and is working totally fine atleast for me. just add this to vite.config.ts

resolve: {
    alias: {
      ".prisma/client/index-browser": "./node_modules/.prisma/client/index-browser.js"
    }
  }

Note: This is not working with pnpm

Workaround

I have a problem when you are trying to import a @prisma/client into a client-bundle. Despite the error, it makes little sense, because the prisma still can not work in the browser.

There is only one exception: Types. The prisma is difficult to tree-shaking, and if you import only one enum, it will try to include the whole @prisma/client in your bundle and runtime errors.

import { UserRoleEnum } from '@prisma/client'
// imported @prisma/client -> '.prisma/client' -> '@prisma/client/runtime/index'

The workaround is quite simple.

  1. If you only need a type, then import enum as a type. This ensures that prism imports will only exist at compile time and will not be bundled.
// app.ts
import type { UserRoleEnum } from '@prisma/client'
type Props = { role: UserRoleEnum  }
  1. If you want to use enum in runtime, here’s a trick. In a separate file, you need to re-export the TYPE from the prism, but add an enum implementation for runtime.
// my-enums/user-role.ts

// Import original enum as type
import type { UserRoleEnum as UserRoleEnumOrigin } from '@prisma/client'

// Guarantee that the implementation corresponds to the original type
export const UserRoleEnum: { [k in UserRoleEnumOrigin ]: k } = {
  Role1: 'Role1',
  Role2: 'Role2',
} as const

// Re-exporting the original type with the original name
export type UserRoleEnum = UserRoleEnumOrigin
// app.ts
import { UserRoleEnum } from 'my-enums/user-role.ts'

console.log(UserRoleEnum.Role1)
console.log(UserRoleEnum.Role3) // Property 'Role3' does not exist on type '{ Role1: "Role1"; Role2: "Role2"; }'. 

This could have been avoided if the prisma had written all the enums in separate files. Then we could import a specific enum directly from the prisma without any problems

import { UserRoleEnum } from '@prisma/client/enums/UserRoleEnum'

Upd

For TypeScript 4.9 you may use satisfies and re-export prisma’s enums

// my-enums/user-role.ts

// Import original type
import type { UserRoleEnum as UserRoleEnumOrigin } from '@prisma/client'

// Re-export enum for runtime
export const UserRoleEnum = {
  Role1: 'Role1',
  Role2: 'Role2',
} satisfies UserRoleEnumOrigin 

ok not the perfect solution but this works.

package.json

"prisma:inline": "cp ./node_modules/.prisma/client/*.js ./node_modules/@prisma/client",
"prisma:migrate": "prisma migrate deploy && npm run prisma:inline",
"prisma:migrate:dev": "prisma migrate dev && npm run prisma:inline",
"prisma:generate": "prisma generate && npm run prisma:inline"

just copy js files from .prisma/client to @prisma/client everytime you generate.

Just in case, I’ve managed to get a simpler version of that hacky ^ but working solution (platform agnostic). That regex looked terrifying haha

// vite.config.ts
import { createRequire } from 'module'
import path from 'path'
import { defineConfig } from 'vite'

const { resolve } = createRequire(import.meta.url)

const prismaClient = `prisma${path.sep}client`

const prismaClientIndexBrowser = resolve('@prisma/client/index-browser').replace(`@${prismaClient}`, `.${prismaClient}`)

export default defineConfig(() => ({
   resolve: { alias: { '.prisma/client/index-browser': path.relative(__dirname, prismaClientIndexBrowser) } },
}))

Problem

ok the problem is in @prisma/client import string is starting with .

Solutions

Note Sorry for my last assumption, I was wrong.

After serving the built index.html file with express, I encountered several errors due to the lack of access to enums from prisma. I tried your suggested solution but it didn’t work because I am on Windows.

Therefore, I came up with a more generic solution that addresses the issue with the slashes in pathname. I hope it works on other operating systems, would you mind checking it on your setup?

// vite.config.ts
import { createRequire } from 'module'
import path from 'path'
import { defineConfig } from 'vite'

const require = createRequire(import.meta.url)

const prismaClient = require
   .resolve('@prisma/client')
   .replace(/@prisma(\/|\\)client(\/|\\)index\.js/, '.prisma/client/index-browser.js')

const prismaIndexBrowser = path.normalize(path.relative(process.cwd(), prismaClient))

export default defineConfig(() => ({
   resolve: { alias: { '.prisma/client/index-browser': prismaIndexBrowser } },
}))

It’s not svelte-specific. I fot same issue with nuxt 3 in production build in heroku

Just in case, I’ve managed to get a simpler version of that hacky ^ but working solution (platform agnostic). That regex looked terrifying haha

// vite.config.ts
import { createRequire } from 'module'
import path from 'path'
import { defineConfig } from 'vite'

const { resolve } = createRequire(import.meta.url)

const prismaClient = `prisma${path.sep}client`

const prismaClientIndexBrowser = resolve('@prisma/client/index-browser').replace(`@${prismaClient}`, `.${prismaClient}`)

export default defineConfig(() => ({
   resolve: { alias: { '.prisma/client/index-browser': path.relative(__dirname, prismaClientIndexBrowser) } },
}))

Works with sveltekit that uses pnpm, can run build and preview commands and no errors 🎉 . Platform is mac intel, gonna deploy this to prod and see if it stays working on linux.

Of course, you can ask, but the answer is pretty obvious: Because we had and have other things to do. We can only work on so many things, and this did not make the top of the list. If another tool gives you all you need, then of course you should use that.

Can I ask, why is this still an issue one year on from the original bug report? Can the priority for this be bumped? Currently on 4.11.0. Thinking about Drizzle ORM at this point …

I just wasted a bunch of time on this, huge bummer. Simply importing anything in the same file as a Prisma.validator call from the client brings the entire thing to a halt with the following error in the browser (Firefox 121.0.1 AND Safari Version 17.1):

TypeError: The specifier “.prisma/client/index” was a bare specifier, but was not remapped to anything. Relative module specifiers must start with “./”, “../” or “/”.

The alias solution above works for me but seems like we shouldn’t have to do something like that… I have created a minimum reproduction repo @jharrell

https://github.com/diericx/prisma-validator-issue

$ node --version
v21.5.0
$ sw_vers
ProductName:		macOS
ProductVersion:		14.1
BuildVersion:		23B73

Relevant package info from the repo above:

{
  "prisma": "^5.8.1",
  "vite": "^5.0.12",
}
import { createRequire } from 'module'
import path from 'path'
import { defineConfig } from 'vite'

const require = createRequire(import.meta.url)

const prismaClient = require
   .resolve('@prisma/client')
   .replace(/@prisma(\/|\\)client(\/|\\)index\.js/, '.prisma/client/index-browser.js')

const prismaIndexBrowser = path.normalize(path.relative(process.cwd(), prismaClient))

export default defineConfig(() => ({
   resolve: { alias: { '.prisma/client/index-browser': prismaIndexBrowser } },
}))

This seems to have resolved the issue for me, so big thanks to you @sharmapukar217! 🙏

Note Sorry for my last assumption, I was wrong.

After serving the built index.html file with express, I encountered several errors due to the lack of access to enums from prisma. I tried your suggested solution but it didn’t work because I am on Windows.

Therefore, I came up with a more generic solution that addresses the issue with the slashes in pathname. I hope it works on other operating systems, would you mind checking it on your setup?

// vite.config.ts
import { createRequire } from 'module'
import path from 'path'
import { defineConfig } from 'vite'

const require = createRequire(import.meta.url)

const prismaClient = require
   .resolve('@prisma/client')
   .replace(/@prisma(\/|\\)client(\/|\\)index\.js/, '.prisma/client/index-browser.js')

const prismaIndexBrowser = path.normalize(path.relative(process.cwd(), prismaClient))

export default defineConfig(() => ({
   resolve: { alias: { '.prisma/client/index-browser': prismaIndexBrowser } },
}))

Sure I’ll check it on morning. It’s midnight and my laptop is off so I’ll inform you if this works on Ubuntu or not 🙂

ok not the perfect solution but this works.

package.json

"prisma:inline": "cp ./node_modules/.prisma/client/*.js ./node_modules/@prisma/client",
"prisma:migrate": "prisma migrate deploy && npm run prisma:inline",
"prisma:migrate:dev": "prisma migrate dev && npm run prisma:inline",
"prisma:generate": "prisma generate && npm run prisma:inline"

just copy js files from .prisma/client to @prisma/client everytime you generate.

the workaround is simple by just setting the output path in prisma.scheme to node_modules/@prisma/client/.prisma/client/ without any copying.

generator client {
  provider = "prisma-client-js"
  output   = "node_modules/@prisma/client/.prisma/client/"
}

remember primsa generate after updating @prisma/client package.

1️⃣ Reproduce?

I cloned your repo but was not able to produce any error. you can with your reproduction repo? Or you stripped out too many things?

2️⃣ My issue was

I looked up in my git history, and I was wrong in my previous comment. The issue was happening when I was importing enums like:

import { my_cool_enum } from '@prisma/client';
let data = my_cool_enum.ELEMENT1;

To overcome this, I need to do it like:

let data = 'ELEMENT1';

Maybe it’s something similar that you have?

3️⃣ Prisma client for dev & preview

I’m using this way to init my client and it’s working well;

import Prisma, * as PrismaScope from '@prisma/client';
const PrismaClient = Prisma?.PrismaClient || PrismaScope?.PrismaClient;

export const PrismaClientKnownRequestError =
	Prisma?.Prisma.PrismaClientKnownRequestError || PrismaScope?.Prisma.PrismaClientKnownRequestError;
export const prismaInstance = new PrismaClient();
export default prismaInstance;

(Actually, I don’t use the default export but directly prismaInstance. But this worked well also with your repo.)

i got a solution and is working totally fine atleast for me. just add this to vite.config.ts

resolve: {
    alias: {
      ".prisma/client/index-browser": "./node_modules/.prisma/client/index-browser.js"
    }
  }

Note: This is not working with pnpm

https://github.com/prisma/prisma/issues/12504#issuecomment-1285883083

This does work.

Though many people use . '.prisma/client/index-browser': './node_modules/.prisma/client/index-browser.js', I have to use @ '.prisma/client/index-browser': './node_modules/@prisma/client/index-browser.js',

Also, pnpm run build works for me.

import { createRequire } from 'module'
import path from 'path'
import { defineConfig } from 'vite'

const require = createRequire(import.meta.url)

const prismaClient = require
   .resolve('@prisma/client')
   .replace(/@prisma(\/|\\)client(\/|\\)index\.js/, '.prisma/client/index-browser.js')

const prismaIndexBrowser = path.normalize(path.relative(process.cwd(), prismaClient))

export default defineConfig(() => ({
   resolve: { alias: { '.prisma/client/index-browser': prismaIndexBrowser } },
}))

This seems to have resolved the issue for me, so big thanks to you @sharmapukar217! 🙏

This worked for me, thanks @nickyhajal! FWIW, I’m using prisma v5.3.1, no problems in dev but typeerror on local build and deploy to vercel. This fixed it.

@danielimmke thanks for the info! Are you (or anyone else in this thread 😃 ) still having this issue? We believe that this should be resolved in 5.0 or later.

I can confirmed that this is not fixed/resolved in 5.0 or later. THis has been an issue for us running 5.3.1

We’re having the same issue using Nuxt3 + prisma 5.3.1 so I can confirm the issue is still present.

I am under the gun with a deadline right now, but I will make a note to see if I can try to reproduce this for you this weekend.

Not quite, perhaps that repo is not quite the reproduction we’re looking for. I haven’t had time today to work on the reproduction repository, but I will have if ready soon.

We essentially need a vite frontend setup, and inside that setup if we import, e.g., Prisma and use Prisma.Decimal.isDecimal() it will show this error. For me, I was creating a tRPC transformer for handling decimals, and the same transformer is needed on the front end as the back end for type inference and serialisation to work correctly.

In issue I have found, is even if I import from a project that has prisma listed as a dependency into a vite project - I see this error. I can only import types that get stripped at compilation / build time.

I’ll have more information soon.

Note: This is not working with pnpm this seems to work with any of the package manager even with pnpm… a bit hacky but atleast works

import { createRequire } from "module";

const prismaPlugin = () => {
	const require = createRequire(import.meta.url);
	const pathName = require
		.resolve("@prisma/client")
		.replace("@prisma/client/index.js", "");

	return {
		name: "prisma-vite-plugin",
		config: () => ({
			resolve: {
				alias: {
					".prisma/client/index-browser": `${pathName}.prisma/client/index-browser.js`
				}
			}
		})
	};
};

export default defineConfig({
	plugins: [whatever(), prismaPlugin()],
});


// or without plugin
const require = createRequire(import.meta.url);
const pathName = require.resolve("@prisma/client").replace("@prisma/client/index.js", "");

export default defineConfig({
	plugins: [whatever()],
        resolve: {
           alias: {
		".prisma/client/index-browser": `${pathName}.prisma/client/index-browser.js`
           }
       }
})

i got a solution and is working totally fine atleast for me. just add this to vite.config.ts

resolve: {
    alias: {
      ".prisma/client/index-browser": "./node_modules/.prisma/client/index-browser.js"
    }
  }

worked for me. thank you!

Any update on this? Still having issues.

@devi4nt @Chadyka do you have reproduction repos available? That would really help us understand what we missed in our fix. Any reproduction you can give us would be immensely helpful.

This was not an issue in my project using vite@4.1.4 with prisma@5.0.0. I only upgraded vite to @4.4.7 and this issue appeared. Still w prisma@5.0.0.

@kuubson 's workaround worked flawlessly for me, and is a simple workaround until the issue is resolved, probably from vite’s end. Much thanks to them and the other helpers.

Lots of people are having this problem, with the solution I found being so different from the other ones presented, I’m as baffled as everybody else but will share my experience debugging this in case it helps unearth some arcane glitch or identify a point that needs to be made clearer in the documentation, perhaps not even as a description of Prisma’s behavior as much as a “tons of people get this wrong, here’s a common pitfall to avoid” footnote. I spent this morning, yesterday, and the day before trying to figure out what was causing this issue for me. The issue:

npm run dev = runs flawlessly. Pushing to github → Vercel, with package.json scripts I tested in two configurations (C, I tried after I found the solution): A

"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate && prisma migrate deploy && prisma generate",

B

"build": "nuxt build && prisma migrate deploy && prisma generate",
"dev": "nuxt dev",
"generate": "nuxt generate",

C

"build" "prisma migrate deploy && prisma generate && nuxt build"
...B

and no modifications of vercel’s defaults, however, led to two pages breaking as pictured:

image

I am using Nuxt 3.3.2 and Prisma 4.12. I had this problem with two pages on my site not working, pages/…/pic/[picTitle] and /pages/tag/[tagName]. I have SSR set to false for tag/** and pic/**. Into the broken two pages, I was importing a couple validation functions from a file /types/models.ts that imported

import { Prisma } from "@prisma/client";
import { Art, BlogPost, Tag, TagsOnArt } from ".prisma/client";

and has a couple Prisma.validators to determine the types. I also exported a type-validating function from this file.

const blogPostWithTags = Prisma.validator<Prisma.BlogPostArgs>()({
  include: {
    tags: {
      include: {
        tag: true,
      },
    },
  },
});
export type BlogPostWithTags = Prisma.BlogPostGetPayload<
  typeof blogPostWithTags
>;

const artWithTags = Prisma.validator<Prisma.ArtArgs>()({
  include: {
    tags: {
      include: {
        tag: true,
      },
    },
  },
});
export type ArtWithTags = Prisma.ArtGetPayload<typeof artWithTags> & {
  url?: string;
  artists?: string[];
};
export function validateArtWithTags(obj: any): obj is ArtWithTags {
  if (
    typeof obj.title === "string" &&
    (!obj.info || typeof obj.info === "string") &&
    typeof obj.published === "boolean" &&
    Array.isArray(obj.tags)
  ) {
    return true;
  }
  return false;
}

I exported this blog type and another to a page that worked, and art types to a page that didn’t. For some reason, although I have very similar logic between my blog post page and my art page, the art and tag pages were breaking yet not my blog. Weirder still is the tag description page, which wasn’t working, uses a much simpler function:

export const validateTag = function (maybeTag: any): maybeTag is Tag {
  if (
    ["id", "name", "info"].every((property) =>
      Object.keys(maybeTag).includes(property)
    )
  ) {
    return true;
  }
  return false;
};

I tried messing with a lot of the page SFC typescript, since @Prisma and .prisma seemed likely culprits and the pages were what weren’t working. But when I started to realize that there is magic happening between the two aforementioned prisma folders, and @Prisma is supposed to be the “official” library, which then exports stuff from the generated library, I wondered if at some step in the build, maybe at some point in building/generating process, code is being run in a context where it doesn’t have the right access to certain references. One thing my two broken pages had in common, in contrast to my other pages using the code here, was that I was not just using exported types, but calling these functions. These are the only times that I’m executing code from this file, where Prisma.ArtArgs is referenced, with Prisma being imported from @prisma rather than .prisma. Perhaps at the time where vite (common between nuxt 3 and sveltekit) is building the page, it has lost or not yet made a connection between the @prisma npm package and generated code in .prisma. I suspect it’s “not yet” because the deployment process involves clean installs and has to then generate stuff for @prisma to reference.

Testing this theory gave positive evidence. My pages are no longer broken (commit that fixed it) after simply copying and pasting what Intellisense generated to replace the validator functions and subsequent Prisma.ModelGetPayload<typeof modelValidator> convention that is suggested in the Prisma documentation. I didn’t even have to change the type-validating function I was exporting after I swapped the earlier type-generating code out for this:

export type BlogPostWithTags = BlogPost & {
  tags: (TagsOnPosts & {
    tag: Tag;
  })[];
};
export type ArtWithTags = Art & {
  tags: (TagsOnArt & {
    tag: Tag;
  })[];
} & {
  url?: string | undefined;
  artists?: string[] | undefined;
};

image

What I think we collectively need a better understanding of and ramification explanation for is: what code one can access in what contexts at what stages of build/runtime. I didn’t see anybody on this thread mention what order their build script Perhaps the documentation could suggest that developers use these validator functions to generate the types, but replace them the types generated by Intellisense. If you are using Prisma.[generated code] but you’re importing from the npm package @prisma, it seems like one needs to be mindful of when the .prisma client is generated, which must happen for its generated features (e.g. Prisma.YourCustomModelArgs) to be usable by @prisma.

This is when I tested what would happen if I switched up the order of the build command (i.e. `“nuxt build && prisma generate” → “prisma generate && nuxt build”) and reverted my code. This returned it to a broken state!

Hopefully this helps somebody. If you’re getting this error, look at whether there are files where the frontend might call code from files where you have:

import { Prisma } from "@prisma/client";
Prisma.[generatedCode]

Of course, you can ask, but the answer is pretty obvious: Because we had and have other things to do. We can only work on so many things, and this did not make the top of the list. If another tool gives you all you need, then of course you should use that.

Surely ongoing bugs and fixes should be priority for your users??

@shtse8 if my memory is not failing me, i tried doing that before sending my solution. it didnt work for me but gonna look into it again