apollographql / apollo-client

:rocket:  A fully-featured, production ready caching GraphQL client for every UI framework and GraphQL server.
https://apollographql.com/client
MIT License
19.33k stars 2.65k forks source link

TypeError [ERR_INVALID_ARG_TYPE]: The "filename" argument must be of type string or an instance of URL. Received an instance of URL #11551

Closed lhguerra closed 7 months ago

lhguerra commented 7 months ago

Issue Description

I'm getting this very weird error trying to use Apollo persisted queries link, as instructed here, and I'm very confused of what it means, since if 'instance of URL' is a valid type and that function is receiving it like that, it shouldn't be a type error.

My client looks like this:

import {
  ApolloClient,
  ApolloLink,
  HttpLink,
  InMemoryCache,
} from "@apollo/client"
import { onError } from "@apollo/client/link/error"
import { createPersistedQueryLink } from "@apollo/client/link/persisted-queries"
import ApolloLinkTimeout from "apollo-link-timeout"
import { sha256 } from "crypto-hash"
import { Agent } from "https"
import { log } from "next-axiom"

const apiUri = process.env.NEXT_PUBLIC_GRAPHQL_API_URL

const httpLink = new HttpLink({
  uri: apiUri,
  fetchOptions: {
    agent: new Agent({ keepAlive: true }),
    next: {
      revalidate: 300,
    },
  },
})

const timeoutLink = new ApolloLinkTimeout(15_000)

const errorLink = onError(({ graphQLErrors, networkError, operation }) => {
  if (graphQLErrors)
    graphQLErrors.forEach(({ message, locations, path }) =>
      log.error(
        `[GraphQL error]: Message: ${message}, Location: ${JSON.stringify(
          locations
        )}, Path: ${path}, operation: ${operation.operationName}`
      )
    )
  if (networkError) {
    if (networkError.message.includes("Timeout exceeded")) {
      log.error(`Timeout exceeded Operation Name: ${operation.operationName}`)
    } else {
      log.error(
        `[Network error]: ${networkError}, operation: ${operation.operationName}`
      )
    }
  }
})

const persistedQueriesLink = createPersistedQueryLink({
  sha256,
  useGETForHashedQueries: true,
})

const links = process.env.VERCEL_ENV
  ? [errorLink, timeoutLink, persistedQueriesLink, httpLink]
  : [errorLink, persistedQueriesLink, httpLink]

export const apolloLink = ApolloLink.from(links)

const isClient = typeof window !== "undefined"

const client = new ApolloClient({
  ssrMode: true,
  link: apolloLink,
  cache: new InMemoryCache(),
  defaultOptions: {
    query: {
      fetchPolicy: isClient ? "cache-first" : "no-cache",
      errorPolicy: "all",
    },
  },
})

export default client

Link to Reproduction

.

Reproduction Steps

No response

@apollo/client version

3.9.1

phryneas commented 7 months ago

This could maybe be an error message from esbuild. Can you please also share all your imports from the affected files?

Also, can you please give us some information when you are getting this error? Is this during build or in the browser?

lhguerra commented 7 months ago

There is a ton of affected files, which contents I also cant share. The error happens whenever a query runs. It might be worth to add that the queries are running in React Server Components, using Next 14 and app router.

I get the error both on build time and runtime, but if I disable SWC support in next.config.js it only happens in runtime.

phryneas commented 7 months ago

The thing is, nothing in the whole source code of Apollo Client tries to access anything with a filename property. This error might be coming from your bundler, but with the current level of information I can only guess.

With just the error message, not even a stack trace and no other pointers, we can't really help you - you'll have to share more information with us for us to be able to look into this.

Maybe you could at least share the stack trace and show us how you import persistedQueriesLink?

lhguerra commented 7 months ago

I updated the issue description with the whole code of my Apollo Link. I'm using it in a Next 14 application with app router and the queries run in a server component.

One other thing is that im using the experimental support lib and the link in the description is used with the registerApolloClient function:

import { registerApolloClient } from "@apollo/experimental-nextjs-app-support/rsc"
import client from "@src/lib/apolloClient"

export const { getClient } = registerApolloClient(() => client)
lhguerra commented 7 months ago

Oh and of course the buildtime error (which I can work around by disabling swc support in next.config):

➜  webapp git:(fs/persisted-queries) ✗ npm run build

> webapp@0.1.0 build
> next build

   ▲ Next.js 14.1.0
   - Environments: .env.local

   Creating an optimized production build ...
Failed to compile.

static/media/thread.2465a67c.js from Terser
  x 'import', and 'export' cannot be used outside of module code
   ,-[1:1]
 1 | import { Buffer } from "node:buffer";
   : ^^^^^^
 2 | import crypto from "node:crypto";
 3 | import { parentPort } from "node:worker_threads";
 4 | parentPort.on("message", (message)=>{
   `----

Caused by:
    0: failed to parse input file
    1: Syntax Error
Error: 
  x 'import', and 'export' cannot be used outside of module code
   ,-[1:1]
 1 | import { Buffer } from "node:buffer";
   : ^^^^^^
 2 | import crypto from "node:crypto";
 3 | import { parentPort } from "node:worker_threads";
 4 | parentPort.on("message", (message)=>{
   `----

Caused by:
    0: failed to parse input file
    1: Syntax Error

> Build failed because of webpack errors

And the runtime error (which I still can't work around and names this issue)

✓ Compiled /[lng] in 16s (3571 modules)
 ⨯ node_modules/@apollo/client/errors/index.js (39:27) @ call
 ⨯ ApolloError: The "filename" argument must be of type string or an instance of URL. Received an instance of URL
    at new Promise (<anonymous>)
    at Array.forEach (<anonymous>)
null
phryneas commented 7 months ago

One other thing is that im using the experimental support lib and the link in the description is used with the registerApolloClient function:


import { registerApolloClient } from "@apollo/experimental-nextjs-app-support/rsc"
import client from "@src/lib/apolloClient"

export const { getClient } = registerApolloClient(() => client)



Please never do that!

It's extremely important that the `client` instance is created **inside** the `registerApolloClient` function - otherwise you will be sharing a client instance between all your users, potentially leaking private data between users. Next.js will keep running between requests and something like a module-global `client` variable/export would be shared between users.
phryneas commented 7 months ago

✓ Compiled /[lng] in 16s (3571 modules) ⨯ node_modules/@apollo/client/errors/index.js (39:27) @ call ⨯ ApolloError: The "filename" argument must be of type string or an instance of URL. Received an instance of URL at new Promise () at Array.forEach () null

This seems to be from further up the network chain - can you expand that error in your console, and log error.networkError to show the parent error?

lhguerra commented 7 months ago

Regarding the client being shared, it is not an issue since this product is all about public content, there is no user data being transfered, but thanks for the tip!

The network error is the same one I opend the issue with:

error - [Network error]: TypeError [ERR_INVALID_ARG_TYPE]: The "filename" argument must be of type string or an instance of URL. Received an instance of URL, operation: Home
phryneas commented 7 months ago

Regarding the client being shared, it is not an issue since this product is all about public content, there is no user data being transfered, but thanks for the tip!

Also keep in mind that you might end up with outdated data if the server runs for a long time. We will likely add a console warning about this in the future. Apollo Client is meant for long-running sessions in the browser, not really on the server.

The network error is the same one I opend the issue with

Yes, but does that nested error have a stack trace that tells us where it's coming from? My guess is that it's somehwere from the Next.js fetch implementation, but I can't know for sure.

lhguerra commented 7 months ago

Also keep in mind that you might end up with outdated data if the server runs for a long time. We will likely add a console warning about this in the future.

This is not an issue rn because I'm running everything serverless.

Concerning the error, I wasn't able to log all of it but now I got it

Error: The "filename" argument must be of type string or an instance of URL. Received an instance of URL

Call Stack
call
node_modules/@apollo/client/errors/index.js (39:27)
eval
node_modules/@apollo/client/core/QueryManager.js (777:70)
examiner
node_modules/@apollo/client/utilities/observables/asyncMap.js (22:30)
callback
node_modules/@apollo/client/utilities/observables/asyncMap.js (11:71)
new Promise
<anonymous>
Object.then
node_modules/@apollo/client/utilities/observables/asyncMap.js (11:23)
then
node_modules/@apollo/client/utilities/observables/asyncMap.js (24:48)
call
node_modules/zen-observable-ts/module.js (137:17)
notifySubscription
node_modules/zen-observable-ts/module.js (176:2)
onNotify
node_modules/zen-observable-ts/module.js (229:4)
argument
node_modules/@apollo/client/utilities/observables/iteration.js (7:68)
Array.forEach
<anonymous>
forEach
node_modules/@apollo/client/utilities/observables/iteration.js (7:24)
_this
node_modules/@apollo/client/utilities/observables/Concast.js (76:43)
call
node_modules/zen-observable-ts/module.js (137:17)
notifySubscription
node_modules/zen-observable-ts/module.js (176:2)
onNotify
node_modules/zen-observable-ts/module.js (229:4)
error
node_modules/@apollo/client/link/error/index.js (49:33)
call
node_modules/zen-observable-ts/module.js (137:17)
notifySubscription
node_modules/zen-observable-ts/module.js (176:2)
onNotify
node_modules/zen-observable-ts/module.js (229:4)
phryneas commented 7 months ago

That looks like the "outer" stack, as in error.stack - what I'm looking for is error.networkError.stack. Can you get that, too?

lhguerra commented 7 months ago

I guess you mean this?

TypeError [ERR_INVALID_ARG_TYPE]: The "filename" argument must be of type string or an instance of URL. Received an instance of URL
    at new NodeError (node:internal/errors:405:5)
    at new Worker (node:internal/worker:158:15)
    at createWorker (webpack-internal:///(rsc)/./node_modules/crypto-hash/index.js:28:18)
    at eval (webpack-internal:///(rsc)/./node_modules/crypto-hash/index.js:46:17)
    at new Promise (<anonymous>)
    at taskWorker (webpack-internal:///(rsc)/./node_modules/crypto-hash/index.js:42:47)
    at eval (webpack-internal:///(rsc)/./node_modules/crypto-hash/index.js:65:34)
    at generateHash (webpack-internal:///(rsc)/./node_modules/@apollo/client/link/persisted-queries/index.js:74:32)
    at eval (webpack-internal:///(rsc)/./node_modules/@apollo/client/link/persisted-queries/index.js:79:28)
    at new Promise (<anonymous>)
    at getHashPromise (webpack-internal:///(rsc)/./node_modules/@apollo/client/link/persisted-queries/index.js:78:16)
    at getQueryHash (webpack-internal:///(rsc)/./node_modules/@apollo/client/link/persisted-queries/index.js:93:52)
    at eval (webpack-internal:///(rsc)/./node_modules/@apollo/client/link/persisted-queries/index.js:202:17)
    at new Subscription (webpack-internal:///(rsc)/./node_modules/zen-observable-ts/module.js:204:40)
    at Observable.subscribe (webpack-internal:///(rsc)/./node_modules/zen-observable-ts/module.js:266:16)
    at eval (webpack-internal:///(rsc)/./node_modules/@apollo/client/link/error/index.js:19:42)
    at new Subscription (webpack-internal:///(rsc)/./node_modules/zen-observable-ts/module.js:204:40)
    at Observable.subscribe (webpack-internal:///(rsc)/./node_modules/zen-observable-ts/module.js:266:16)
    at Object.complete (webpack-internal:///(rsc)/./node_modules/@apollo/client/utilities/observables/Concast.js:128:43)
    at Concast.start (webpack-internal:///(rsc)/./node_modules/@apollo/client/utilities/observables/Concast.js:171:23)
    at new Concast (webpack-internal:///(rsc)/./node_modules/@apollo/client/utilities/observables/Concast.js:157:19)
    at QueryManager.getObservableFromLink (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:775:35)
    at QueryManager.getResultsFromLink (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:814:83)
    at resultsFromLink (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:1116:26)
    at QueryManager.fetchQueryByPolicy (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:1212:25)
    at fromVariables (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:882:41)
    at QueryManager.fetchConcastWithInfo (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:923:35)
    at QueryManager.fetchQuery (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:422:21)
    at QueryManager.query (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/QueryManager.js:531:21)
    at ApolloClient.query (webpack-internal:///(rsc)/./node_modules/@apollo/client/core/ApolloClient.js:206:34)
    at SportLayout (webpack-internal:///(rsc)/./app/[lng]/(sport)/layout.tsx:29:93)
    at ej (/home/luiz/www/myProject/myProject/webapp/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:264151)
    at /home/luiz/www/myProject/myProject/webapp/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:276953
    at Array.toJSON (/home/luiz/www/myProject/myProject/webapp/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:281723)
    at stringify (<anonymous>)
    at /home/luiz/www/myProject/myProject/webapp/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:268079
    at ez (/home/luiz/www/myProject/myProject/webapp/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:268158)
    at eH (/home/luiz/www/myProject/myProject/webapp/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:268559)
    at AsyncLocalStorage.run (node:async_hooks:338:14)
    at Timeout._onTimeout (/home/luiz/www/myProject/myProject/webapp/node_modules/next/dist/compiled/next-server/app-page.runtime.dev.js:35:282165)
    at listOnTimeout (node:internal/timers:569:17)
    at process.processTimers (node:internal/timers:512:7) {
  code: 'ERR_INVALID_ARG_TYPE'
}
phryneas commented 7 months ago

Yes! It seems the crypto-hash module wants to do things in a worker process and the Next.js webpack cannot work with that?

For what it's worth, you don't need an external package for that, modern node can already do that:

import crypto from "node:crypto";
function sha256(data: string) {
  const hash = crypto.createHash("sha256");
  hash.update(data);
  return hash.digest("hex");
}
lhguerra commented 7 months ago

I just had to change the import to import crypto from "crypto" but now I'm getting 500 from the server which means the issue moved to the backend part of the stack which means this issue is solved :sweat_smile:

Thank you very much!

github-actions[bot] commented 7 months ago

Do you have any feedback for the maintainers? Please tell us by taking a one-minute survey. Your responses will help us understand Apollo Client usage and allow us to serve you better.

phryneas commented 7 months ago

Happy to help, I hope you can resolve your other problem, soon, too!

I've also answered to your StackOverflow question - maybe the answer there helps someone else in the future :)

github-actions[bot] commented 6 months ago

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs. For general questions, we recommend using StackOverflow or our discord server.