David
David13mo ago

"fetch failed" when building

Hi, we are running into an issue where building our production next app causes "fetch failed" errors for every page that is being generated. We have ssr set to false. How can we debug this?
TRPCClientError: fetch failed
at TRPCClientError.from (file:///home/david/mrb-docker-dev/www/mrb-monorepo/node_modules/.pnpm/@trpc+client@10.43.3_@trpc+server@10.43.3/node_modules/@trpc/client/dist/TRPCClientError-0de4d231.mjs:37:16)
at file:///home/david/mrb-docker-dev/www/mrb-monorepo/node_modules/.pnpm/@trpc+client@10.43.3_@trpc+server@10.43.3/node_modules/@trpc/client/dist/httpUtils-f58ceda1.mjs:128:36
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
meta: {},
shape: undefined,
data: undefined,
[cause]: TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11372:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
cause: AggregateError
at internalConnectMultiple (node:net:1114:18)
at afterConnectMultiple (node:net:1667:5) {
code: 'ECONNREFUSED',
]: [Array]
}
}
}
TRPCClientError: fetch failed
at TRPCClientError.from (file:///home/david/mrb-docker-dev/www/mrb-monorepo/node_modules/.pnpm/@trpc+client@10.43.3_@trpc+server@10.43.3/node_modules/@trpc/client/dist/TRPCClientError-0de4d231.mjs:37:16)
at file:///home/david/mrb-docker-dev/www/mrb-monorepo/node_modules/.pnpm/@trpc+client@10.43.3_@trpc+server@10.43.3/node_modules/@trpc/client/dist/httpUtils-f58ceda1.mjs:128:36
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
meta: {},
shape: undefined,
data: undefined,
[cause]: TypeError: fetch failed
at Object.fetch (node:internal/deps/undici/undici:11372:11)
at process.processTicksAndRejections (node:internal/process/task_queues:95:5) {
cause: AggregateError
at internalConnectMultiple (node:net:1114:18)
at afterConnectMultiple (node:net:1667:5) {
code: 'ECONNREFUSED',
]: [Array]
}
}
}
11 Replies
David
DavidOP13mo ago
We looked through github, this Discord server etc but all the solutions there don't work. Usually people actually want to be fetching as SSR or something but that is not the case with us so we don't understand why it even attempts to fetch something @Alex / KATT 🐱 Sorry, prefer not to tag people but been stuck at this for a while and i've got 0 clue how to continue. Any ideas?
Nick
Nick13mo ago
Econnrefused probably means you’re pointing at the wrong uri
David
DavidOP13mo ago
Appreciate the reply! This is during build though, it shouldn't be trying to fetch anything anyway, so im not sure at what point or why it is attempting to
Nick
Nick13mo ago
That might mean you’ve put a fetch somewhere which calls on build NextJS and others do have APIs for this
David
DavidOP13mo ago
Have looked through the commit where it started several times, I can't find anything that would cause this. All our fetches/hook calls are inside of components, nothing at the root level. Any idea how I could see a better stack trace that may lead to where its coming from? We did add prefetching in this commit on a page, but that is inside of a gssp.
Nick
Nick13mo ago
I’d start restricting the problem space, print a lot more info from the api to see what the calls are and if the request is reaching it Try adding an onError to your adapter Then commenting out parts of the app if that doesn’t help, basically binary searching your components These types of issues are a pain but not something we can support massively with since it’s likely a setup mistake
David
DavidOP13mo ago
Will try these things, thank you for the responses! So, some observations: The request is happening even before the browser renders, it does not show in the network tab in the browser, there are no cookies attached to the request when logging it on the server side Everything works in the background, as in the browser renders and makes a valid request etc. It does not end up in our root error boundary But any call to that specific procedure causes it. So if I only render that specific query it'll happen, even though I render it as we would anywhere else in some page. Only occurs for this specific procedure, taking out the code it errors on (cookie / auth stuff) fixes it, even though a bunch of other procedures use that same middleware So, we reverted the original PR for a while until we had more time to look at it. It starts when you change this:
// blitz way
return useQuery(ActiveLocalesQuery,
// blitz way
return useQuery(ActiveLocalesQuery,
to this:
return trpc.core.companyProduct.getActiveLocales.useSuspenseQuery(undefined, {
return trpc.core.companyProduct.getActiveLocales.useSuspenseQuery(undefined, {
1Sonny
1Sonny13mo ago
@David I had this error a while ago too. Fixed by setting localhost to 127.0.0.1 in /etc/hosts in WSL
David
DavidOP13mo ago
mostly confused because it shouldn't be fetching anything initially Changing it to useQuery instead of useSuspenseQuery solves it for now
Alex / KATT 🐱
Alex / KATT 🐱13mo ago
ohhhhh i get what this is now if you use suspense it'll try to fetch the data on the first load on the server which is probably not what you want you prob want something like this if you're using suspense
import type { SuspenseProps } from 'react';
import React, { Suspense, useEffect, useState } from 'react';
import { Spinner } from '~/components/Spinner';

/**
* Whether the app has ever mounted.
* This is used to determine whether to render the fallback on the first render.
*/
let hasEverMounted = false;

/**
* Suspense that doesn't render on the server.
* - On server, it always renders the fallback.
* - On client, it renders the fallback only on the first render.
*/
export function NoSSRSuspense(props: {
children: React.ReactNode;
/**
* Fallback while loading.
* @default <PageSpinner />
*/
fallback?: SuspenseProps['fallback'];
}) {
const [isMounted, setIsMounted] = useState(hasEverMounted);
useEffect(() => {
setIsMounted(true);
hasEverMounted = true;
}, []);
const fallback =
props.fallback === undefined ? <Spinner /> : props.fallback;

return (
<>{isMounted ? <Suspense {...props} fallback={fallback} /> : fallback}</>
);
}
import type { SuspenseProps } from 'react';
import React, { Suspense, useEffect, useState } from 'react';
import { Spinner } from '~/components/Spinner';

/**
* Whether the app has ever mounted.
* This is used to determine whether to render the fallback on the first render.
*/
let hasEverMounted = false;

/**
* Suspense that doesn't render on the server.
* - On server, it always renders the fallback.
* - On client, it renders the fallback only on the first render.
*/
export function NoSSRSuspense(props: {
children: React.ReactNode;
/**
* Fallback while loading.
* @default <PageSpinner />
*/
fallback?: SuspenseProps['fallback'];
}) {
const [isMounted, setIsMounted] = useState(hasEverMounted);
useEffect(() => {
setIsMounted(true);
hasEverMounted = true;
}, []);
const fallback =
props.fallback === undefined ? <Spinner /> : props.fallback;

return (
<>{isMounted ? <Suspense {...props} fallback={fallback} /> : fallback}</>
);
}
David
DavidOP13mo ago
Will try this now! This works! Thank you so much! Do you know why this happens during build? And could it be related to the fact that those queries get called in _app , compared to everything else which is only called on a page