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

ENOENT error when running prisma as /api in next.js #1021

Closed
BjoernRave opened this issue Nov 29, 2019 · 15 comments
Closed

ENOENT error when running prisma as /api in next.js #1021

BjoernRave opened this issue Nov 29, 2019 · 15 comments
Assignees
Labels
bug/2-confirmed Bug has been reproduced and confirmed. kind/bug A reported bug.
Milestone

Comments

@BjoernRave
Copy link

I want to run prisma inside next.js as a /api route. When I was setting it up at first only with the graphql-auth example everything was working fine (beside some problems with typegen with photon, but there's already an issue). Then I changed the schema and added some resolvers and objectTypes and when I wanted to start it again, when going to the route I get the output:

[Error: ENOENT: no such file or directory, mkdir] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'mkdir'
}

and I cannot query the server: "error": "JSON.parse: unexpected character at line 1 column 1 of the JSON data"

When running the same files as a standalone server(with what graphql-auth example provides), it's running fine.

Not sure if it's related to next.js or not, I tried turning on debug on photon and apollo-server, but the only thing I got is:
getos { platform: 'darwin', libssl: undefined } +0ms

Happy to provide more info if needed

@BjoernRave BjoernRave changed the title ENONENT error when running prisma as /api in next.js ENOENT error when running prisma as /api in next.js Nov 29, 2019
@timsuchanek timsuchanek added bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. kind/bug A reported bug. labels Nov 29, 2019
@pantharshit00
Copy link
Contributor

Hi,

I am able to run a simple next js app with Prisma without any problems. You can find the code here: https://github.com/harshit-test-org/prisma-next-routes

image

So can you please provide me with a minimal reproduction of this? You can also try the example that I shared and see whether that works for you.

@pantharshit00 pantharshit00 added bug/0-unknown Bug is new, does not have information for reproduction or reproduction could not be confirmed. and removed bug/1-unconfirmed Bug should have enough information for reproduction, but confirmation has not happened yet. labels Dec 3, 2019
@BjoernRave
Copy link
Author

@pantharshit00 okay, can I add you as a collaborator to my github project for you to see?

@pantharshit00
Copy link
Contributor

Thanks, I got the invite. I will check it out and report back here.

@pantharshit00
Copy link
Contributor

I was able to reproduce it in your repository. I am not really sure what is causing it. Can you please invite @timsuchanek to that repository so that he can take a look as he is currently working on photon internals.

@pantharshit00 pantharshit00 added bug/2-confirmed Bug has been reproduced and confirmed. and removed bug/0-unknown Bug is new, does not have information for reproduction or reproduction could not be confirmed. labels Dec 5, 2019
@BjoernRave
Copy link
Author

BjoernRave commented Dec 5, 2019

@pantharshit00 sure. Done @timsuchanek

@darknoon
Copy link

darknoon commented Dec 5, 2019

I am hitting a similar error with

[Error: ENOENT: no such file or directory, mkdir] {
  errno: -2,
  code: 'ENOENT',
  syscall: 'mkdir'
}

I was able to get it working with this handler (though it still reports the error in the console, and performance is poor though I don't know if that's related):

import { permissions } from "./permissions";
import { schema } from "./schema";
import { createContext } from "./context";
import { ApolloServer } from "apollo-server-micro";
import { applyMiddleware } from "graphql-middleware";

// Good reference: https://github.com/maticzav/graphql-shield/tree/master/examples/with-apollo-server-lambda

const apolloServer = new ApolloServer({
  // schema input replaces typeDefs and resolvers
  schema: applyMiddleware(schema, permissions),
  context: createContext,
  introspection: true,
});

export const config = {
  api: {
    bodyParser: false,
  },
};
const handler = apolloServer.createHandler({ path: "/api/graphql2" });

export default handler;

@BjoernRave
Copy link
Author

BjoernRave commented Dec 5, 2019

@darknoon mine looks pretty much the same:

import { ApolloServer } from "apollo-server-micro";
import { applyMiddleware } from "graphql-middleware";
import { createContext } from "./src/context";
import { permissions } from "./src/permissions";
import { schema } from "./src/schema";

const apolloServer = new ApolloServer({
  schema: applyMiddleware(schema, permissions),
  context: createContext
});

export const config = {
  api: {
    bodyParser: false
  }
};

export default apolloServer.createHandler({ path: "/api/graphql" });

introspection doesn't make any differences

@timsuchanek
Copy link
Contributor

timsuchanek commented Dec 10, 2019

Thanks, everyone for posting the information!

After looking into your reproduction @BjoernRave , I found, that the problem here has nothing to do with prisma2, but it's the combination of next.js and nexus, which doesn't play well.

The problem is, that next.js replaces __dirname with /. This will inevitably make tools fail that rely on it. There were efforts on the Next.js side to fix that, but they got deprioritized.

Concretely, the line https://github.com/prisma-labs/nexus/blob/develop/examples/nexus-prisma/src/index.ts#L144

    schema: path.join(__dirname, './generated/schema.graphql'),

will be rewritten to path.join('/', './generated/schema.graphql') which resolves to //generated/schema.graphql.

Nexus then wants to write there in https://github.com/prisma-labs/nexus/blob/develop/src/typegenMetadata.ts#L101

How can you find that out without the stack trace?
This small hack helps getting the stack trace back for mkdir:

import fs from 'fs'

const oldMkDir: any = fs.mkdir
;(fs as any).mkdir = (...args: any[]) => {
  const err = new Error()
  console.error(`Calling mkdir: ${err.stack}`)
  console.error(`dirname ${__dirname}`)
  return oldMkDir(...args)
}

So a separate issue is, that the stack trace is eaten, which is very likely also a Next.js problem, as nexus just acts a library in this situation.

TL;DR How to get around this problem?

For now, you can e.g. remove the outputs configuration for the makeSchema function of nexus:

export const schema = makeSchema({
  types,
  plugins: [nexusPrismaPlugin()],
  // outputs: {
  //   schema: __dirname + '/generated/schema.graphql',
  //   typegen: __dirname + '/generated/nexus.ts',
  // },
  typegenAutoConfig: {
    sources: [
      {
        source: '@prisma/photon',
        alias: 'photon',
      },
      {
        source: require.resolve('./context'),
        alias: 'Context',
      },
    ],
    contextType: 'Context.Context',
  },
})

You can also try the workaround posted here: vercel/next.js#8251 (comment)

@darknoon
Copy link

@timsuchanek thanks for putting the detail in your writeup. Aren't the outputs required to make typescript work, though? (they weren't in the sample project and I had to add them)

@timsuchanek
Copy link
Contributor

@darknoon if the outputs are not provided, the nexus related parts are typed any. To work with that you probably have to disable the typescript strict mode in your tsconfig.json.

@Weakky
Copy link
Member

Weakky commented Dec 12, 2019

Hey everyone 👋,

@huv1k gave me a workaround. You can create a next.config.js file, and set the following env variable:

// next.config.js
module.exports = {
  env: {
    PROJECT_DIRNAME: __dirname,
  },
}

Then, use that env variable instead of __dirname

import { makeSchema } from 'nexus-prisma'
import { join } from 'path'

const schema = makeSchema({
  outputs: {
    typegen: join(process.env.PROJECT_DIRNAME, 'typegen.ts'),
    schema: join(process.env.PROJECT_DIRNAME, 'schema.ts'),
  }
})

It's not great, but at least it's a working workaround!

@allpwrfulroot
Copy link

allpwrfulroot commented Dec 12, 2019

I'm not able to get that to work on deployment, is there something I missed?

Getting this as a runtime error, in the logs:

2019-12-12T17:58:12.408Z	3edd07ed-b55f-4a08-b8c8-44024dfa3648	INFO	error:  { [Error: ENOENT: no such file or directory, scandir '/zeit/190d26b7/pages/projects']
  errno: -2,
  code: 'ENOENT',
  syscall: 'scandir',
  path: '/zeit/190d26b7/pages/projects' }

That path doesn't match the one given in another error I can provoke,
/var/task/.next/serverless/pages/api/get-projects.js

@timsuchanek
Copy link
Contributor

@allpwrfulroot where are you deploying it to? Optimally you could even post a reproduction repo that we can look into.

@Albert-Gao
Copy link

I found a different approach to this:

const getPath = (fileName: string) =>
  path.join(process.cwd(), "generated", fileName);

// then use it to genetrate the output
    nexusPrismaPlugin({
      outputs: {
        typegen: getPath("nexusPrisma.ts")
      }
    })

@timsuchanek
Copy link
Contributor

Closing due to inactivity, as this seems to be fixed. If you still face this problem, please create a new issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug/2-confirmed Bug has been reproduced and confirmed. kind/bug A reported bug.
Projects
None yet
Development

No branches or pull requests

9 participants