W. Reyna
W. Reyna

Reputation: 724

createReadStream() throwing RangeError: Maximum call stack size exceeded when uploading file

I am trying to use Apollo Server's Upload scalar to send files to S3 directly. My schema:

const { gql } = require('apollo-server-express')

module.exports = gql`

extend type Mutation {
  createPicture(
    name: String!
    picture: Upload!
  ): Picture!
}

type Picture {
  name: String!
  picture: String!
}
`

Resolver:

const { combineResolvers } = require('graphql-resolvers')
const isAuthenticated = require('./auth')
const { uploadPhoto } = require('../services/picture')

module.exports = {
  Mutation: {
    createPicture: combineResolvers(
      isAuthenticated,
      async (
        parent,
        { name, picture = null },
        { models, me }
      ) => {
        const { createReadStream, filename, mimetype, encoding } = await picture
        // Does not get past this line
        const stream = createReadStream()

        uploadPhoto(stream, filename)

        const pictureModel = models.Picture.create({
           name,
           picture
        })
        return pictureModel
      }
    )
  }
}

But my code errors like this:

internal/util.js:55
  function deprecated(...args) {
                     ^

RangeError: Maximum call stack size exceeded
    at ReadStream.deprecated [as open] (internal/util.js:55:22)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)
    at _openReadFs (internal/fs/streams.js:123:12)
    at ReadStream.<anonymous> (internal/fs/streams.js:116:3)
    at ReadStream.deprecated [as open] (internal/util.js:70:15)
    at ReadStream.open ([truncated]/node_modules/fs-capacitor/lib/index.js:90:11)

Note: I am sure the image was sent correctly, as filename is correct

Upvotes: 21

Views: 12930

Answers (9)

Mike
Mike

Reputation: 11

TLDR: Default Apollo server file upload doesn't work in node >=13. Fix it by overwriting Apollo's server file upload with the graphql-upload server file upload

npm install graphql-upload

Overwrite default Apollo Upload type in TypeDefs

const typeDefs = gql`
  scalar Upload
  ...
 `

Overwrite default Apollo Upload type in index.js

const { GraphQLUpload } = require('graphql-upload')
const { graphqlUploadExpress } = require('graphql-upload')
const express = require('express')
 
const app = express()

app.use(graphqlUploadExpress({ 
  maxFileSize: 10000000, 
  maxFiles: 10 
}))

const server = new ApolloServer({
  typeDefs,
  resolvers: {
    Upload: GraphQLUpload,
    ...resolvers
  }
  uploads: false
  ...
})

server.applyMiddleware({
  app
})

Upvotes: 1

BigMan73
BigMan73

Reputation: 1584

I've read the graphql-upload documentation but couldn't find one solid example that shows how to use graph-upload with apollo-server on NodeJS 14. Based on a sample application (that worked on the old graphql-upload version of apollo-server, failed on NodeJS 14) and answers from stack overflow I've managed to create a fully function example.

The original example: https://github.com/DNature/apollo-upload

I used apollo-server-express, instead of apollo-server.

With NodeJS 14, [email protected] and [email protected]:

index.js

import { ApolloServer } from "apollo-server-express";
import express from "express";
import { graphqlUploadExpress } from "graphql-upload";
import typeDefs from "./typeDefs";
import resolvers from "./resolvers";

// Import your database configuration
import connect from "./db";

export default (async function () {
  try {
    await connect.then(() => {
      console.log("Connected 🚀 To MongoDB Successfully");
    });

    const server = new ApolloServer({
      uploads: false, // Disables the bundled ApolloServer old graphql-upload that doesn't work on NodeJS 14
      typeDefs,
      resolvers,
    });
    await server.start();

    const app = express();
    app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
    server.applyMiddleware({ app });

    await new Promise((resolve) => app.listen({ port: 7000 }, resolve));
    console.log(
      `🚀 Server ready at http://localhost:7000${server.graphqlPath}`
    );
  } catch (err) {
    console.error(err);
  }
})();

In typeDefs.gql the scalar Upload needs to be defined:

import { gql } from "apollo-server-express";

export default gql`
  scalar Upload

  type File {
    id: ID!
  ...

In resolvers.js the resolver for Upload needs to be defined:

...

import { GraphQLUpload } from 'graphql-upload';

...

export default {
  Upload: GraphQLUpload,

  Query: {
    hello: () => "Hello world"
  },
  Mutation: {
...

Finally uploading from postman:

Note: the key 0 is of type File, not Text! Upload a file to GraphQL server from postman

Upvotes: 1

pranav shinde
pranav shinde

Reputation: 1650

Add this to your package.json

 "resolutions": {
    "graphql-upload": "^11.0.0"
  }

then add this inside scripts

"scripts": {
    ....
    "preinstall": "npx npm-force-resolutions", //This one
    ....
}

then you need to do npm install. Done

Source: graphql-upload

Upvotes: 1

Everton Castro
Everton Castro

Reputation: 129

Since it is a bug with fs-capacitor, this would help as we can see in this issue

Worked for me in node 14.16.1 with the following configuration:

"resolutions": {
    "fs-capacitor": "^6.2.0",
    "graphql-upload": "^11.0.0"
}

I needed to add force-resolutions inside "scripts"

"scripts": {
    ....
    "preinstall": "npx npm-force-resolutions"
}

Remove ./node_modules and install dependencies again with npm install.

Upvotes: 3

DevAddict
DevAddict

Reputation: 2015

I've been dealing with this problem multiple times

the problem is old graphql-upload more accurately version 8 uses of node open stream function which is deprecated and no longer available in 13.x and older node versions.

so the solution is you can either use nvm to set your node version to 12 or use resolutions in your package.json file. first solution(in your favorite terminal):

nvm install 12; nvm use 12

second solution(in package.json):

"resolutions": {
    "**/**/fs-capacitor":"^6.2.0",
    "**/graphql-upload": "^11.0.0"
  }

also this is a problem I've been dealing with for months and apollo team really doesn't like updating their dependencies I think.

Upvotes: 0

msroot
msroot

Reputation: 837

Using:

    "apollo-server": "^2.18.2",
    "apollo-server-express": "2.18.2",
    "aws-sdk": "^2.771.0",
    "express-fileupload": "^1.2.0",
    "graphql": "^15.3.0",
    "graphql-upload": "^11.0.0",
    "fs-capacitor": "^6.2.0",

I solve this by installing the latest fs-capacitor as a dependency

yarn add fs-capacitor

Upvotes: -2

Meursault
Meursault

Reputation: 315

Add this to package.json:

"resolutions": {
    "**/**/fs-capacitor":"^6.2.0",
    "**/graphql-upload": "^11.0.0"
  }

source: https://github.com/jaydenseric/graphql-upload/issues/170#issuecomment-641938198

Upvotes: 13

Ashish Bastola
Ashish Bastola

Reputation: 341

This error occured to me in node version 14 too! I solved it as follows:

  1. Install latest version of graphql-upload !

  2. use graphqlUploadExpress middleware to define the maximum file limit.

    import { graphqlUploadExpress } from "graphql-upload";
    const app = express()
    app.use(graphqlUploadExpress({ maxFileSize: 1000000000, maxFiles: 10 }));
    
  3. Set uploads to false while initializing the ApolloServer

      const server = new ApolloServer({
        uploads: false,
        schema,
      });
    

Upvotes: 9

W. Reyna
W. Reyna

Reputation: 724

Turns out it was this bug in graphql-upload. Downgraded to node 12 and it's fixed (solution listed there did not help me)

Upvotes: 12

Related Questions