doc-frontend-1          | TypeError: fetch failed
doc-frontend-1          |     at Object.fetch (node:internal/deps/undici/undici:16289:11)
doc-frontend-1          |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
doc-frontend-1          |     at load (/.svelte-kit/adapter-node/entries/pages/languages/_page.server.ts.js:5:20)
doc-frontend-1          |     at load_server_data (/.svelte-kit/adapter-node/index.js:558:18)
doc-frontend-1          |     at <anonymous> (/.svelte-kit/adapter-node/index.js:2041:18) {
doc-frontend-1          |   cause: Error: connect ECONNREFUSED 127.0.0.1:5005
doc-frontend-1          |       at __node_internal_captureLargerStackTrace (node:internal/errors:496:5)
doc-frontend-1          |       at __node_internal_exceptionWithHostPort (node:internal/errors:671:12)
doc-frontend-1          |       at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1549:16) {
doc-frontend-1          |     errno: -111,
doc-frontend-1          |     code: 'ECONNREFUSED',
doc-frontend-1          |     syscall: 'connect',
doc-frontend-1          |     address: '127.0.0.1',
doc-frontend-1          |     port: 5005
doc-frontend-1          |   }
doc-frontend-1          | }

The code is in a +page.server.ts file when it fails. I can do the equivalent in a +page.svelte and it succeeds. I am new to sveltekit, but have researched this issue a lot without success so far.

import { PUBLIC_BACKEND_API_URL, PUBLIC_LANG_CODES_NAMES_URL } from '$env/static/public'
import type { PageServerLoad } from './$types'

export const load: PageServerLoad<{
  langCodeNameAndTypes: Array<[string, string, boolean]>
}> = async () => {
  const url = `${PUBLIC_BACKEND_API_URL}${PUBLIC_LANG_CODES_NAMES_URL}`
  console.log('About to fetch...')
  const response = await fetch(url) // fails here!
  console.log('About to await json()...')
  let langCodeNameAndTypes: Array<[string, string, boolean]> = await response.json()
  if (!response.ok) {
    console.log('response was NOT ok')
    throw new Error(response.statusText)
  }
  console.log('Response was ok, returning it...')
  return { langCodeNameAndTypes }
}

Any ideas?

Update: I tried hardcoding use of http://127.0.0.1:5005/theurlineededtouse as referenced on this github issue provided by @Trevor V in the comments (thanks Trevor), but that did not make a difference.

Update 2: I tried making the same fetch using axios since it provides more info in its stack trace and got the following:

doc-frontend-1          | About to fetch http://127.0.0.1:5005/language_codes_and_names...
doc-frontend-1          | AxiosError: connect ECONNREFUSED 127.0.0.1:5005
doc-frontend-1          |     at AxiosError.from (file:///app/node_modules/axios/lib/core/AxiosError.js:89:14)
doc-frontend-1          |     at RedirectableRequest.handleRequestError (file:///app/node_modules/axios/lib/adapters/http.js:610:25)
doc-frontend-1          |     at RedirectableRequest.emit (node:events:519:28)
doc-frontend-1          |     at eventHandlers.<computed> (/app/node_modules/follow-redirects/index.js:38:24)
doc-frontend-1          |     at ClientRequest.emit (node:events:519:28)
doc-frontend-1          |     at Socket.socketErrorListener (node:_http_client:492:9)
doc-frontend-1          |     at Socket.emit (node:events:519:28)
doc-frontend-1          |     at emitErrorNT (node:internal/streams/destroy:169:8)
doc-frontend-1          |     at emitErrorCloseNT (node:internal/streams/destroy:128:3)
doc-frontend-1          |     at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
doc-frontend-1          |     at Axios.request (file:///app/node_modules/axios/lib/core/Axios.js:45:41)
doc-frontend-1          |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
doc-frontend-1          |     at async load (file:///app/build/server/chunks/5-aKd3-39A.js:7:3)
doc-frontend-1          |     at async load_server_data (file:///app/build/server/index.js:1841:18)
doc-frontend-1          |     at async file:///app/build/server/index.js:3324:18 {
doc-frontend-1          |   port: 5005,
doc-frontend-1          |   address: '127.0.0.1',
doc-frontend-1          |   syscall: 'connect',
doc-frontend-1          |   code: 'ECONNREFUSED',
doc-frontend-1          |   errno: -111,
doc-frontend-1          |   config: {
doc-frontend-1          |     transitional: {
doc-frontend-1          |       silentJSONParsing: true,
doc-frontend-1          |       forcedJSONParsing: true,
doc-frontend-1          |       clarifyTimeoutError: false
doc-frontend-1          |     },
doc-frontend-1          |     adapter: [ 'xhr', 'http' ],
doc-frontend-1          |     transformRequest: [ [Function: transformRequest] ],
doc-frontend-1          |     transformResponse: [ [Function: transformResponse] ],
doc-frontend-1          |     timeout: 0,
doc-frontend-1          |     xsrfCookieName: 'XSRF-TOKEN',
doc-frontend-1          |     xsrfHeaderName: 'X-XSRF-TOKEN',
doc-frontend-1          |     maxContentLength: -1,
doc-frontend-1          |     maxBodyLength: -1,
doc-frontend-1          |     env: { FormData: [Function], Blob: [class Blob] },
doc-frontend-1          |     validateStatus: [Function: validateStatus],
doc-frontend-1          |     headers: Object [AxiosHeaders] {
doc-frontend-1          |       Accept: 'application/json, text/plain, */*',
doc-frontend-1          |       'Content-Type': undefined,
doc-frontend-1          |       'User-Agent': 'axios/1.6.7',
doc-frontend-1          |       'Accept-Encoding': 'gzip, compress, deflate, br'
doc-frontend-1          |     },
doc-frontend-1          |     method: 'get',
doc-frontend-1          |     url: 'http://127.0.0.1:5005/language_codes_and_names',
doc-frontend-1          |     data: undefined
doc-frontend-1          |   },
doc-frontend-1          |   request: <ref *1> Writable {
doc-frontend-1          |     _events: {
doc-frontend-1          |       close: undefined,
doc-frontend-1          |       error: [Function: handleRequestError],
doc-frontend-1          |       prefinish: undefined,
doc-frontend-1          |       finish: undefined,
doc-frontend-1          |       drain: undefined,
doc-frontend-1          |       response: [Function: handleResponse],
doc-frontend-1          |       socket: [Function: handleRequestSocket]
doc-frontend-1          |     },
doc-frontend-1          |     _writableState: WritableState {
doc-frontend-1          |       highWaterMark: 16384,
doc-frontend-1          |       length: 0,
doc-frontend-1          |       corked: 0,
doc-frontend-1          |       onwrite: [Function: bound onwrite],
doc-frontend-1          |       writelen: 0,
doc-frontend-1          |       bufferedIndex: 0,
doc-frontend-1          |       pendingcb: 0,
doc-frontend-1          |       [Symbol(kState)]: 17580812,
doc-frontend-1          |       [Symbol(kBufferedValue)]: null
doc-frontend-1          |     },
doc-frontend-1          |     _maxListeners: undefined,
doc-frontend-1          |     _options: {
doc-frontend-1          |       maxRedirects: 21,
doc-frontend-1          |       maxBodyLength: Infinity,
doc-frontend-1          |       protocol: 'http:',
doc-frontend-1          |       path: '/language_codes_and_names',
doc-frontend-1          |       method: 'GET',
doc-frontend-1          |       headers: [Object: null prototype],
doc-frontend-1          |       agents: [Object],
doc-frontend-1          |       auth: undefined,
doc-frontend-1          |       family: undefined,
doc-frontend-1          |       beforeRedirect: [Function: dispatchBeforeRedirect],
doc-frontend-1          |       beforeRedirects: [Object],
doc-frontend-1          |       hostname: '127.0.0.1',
doc-frontend-1          |       port: '5005',
doc-frontend-1          |       agent: undefined,
doc-frontend-1          |       nativeProtocols: [Object],
doc-frontend-1          |       pathname: '/language_codes_and_names'
doc-frontend-1          |     },
doc-frontend-1          |     _ended: true,
doc-frontend-1          |     _ending: true,
doc-frontend-1          |     _redirectCount: 0,
doc-frontend-1          |     _redirects: [],
doc-frontend-1          |     _requestBodyLength: 0,
doc-frontend-1          |     _requestBodyBuffers: [],
doc-frontend-1          |     _eventsCount: 3,
doc-frontend-1          |     _onNativeResponse: [Function (anonymous)],
doc-frontend-1          |     _currentRequest: ClientRequest {
doc-frontend-1          |       _events: [Object: null prototype],
doc-frontend-1          |       _eventsCount: 7,
doc-frontend-1          |       _maxListeners: undefined,
doc-frontend-1          |       outputData: [],
doc-frontend-1          |       outputSize: 0,
doc-frontend-1          |       writable: true,
doc-frontend-1          |       destroyed: false,
doc-frontend-1          |       _last: true,
doc-frontend-1          |       chunkedEncoding: false,
doc-frontend-1          |       shouldKeepAlive: true,
doc-frontend-1          |       maxRequestsOnConnectionReached: false,
doc-frontend-1          |       _defaultKeepAlive: true,
doc-frontend-1          |       useChunkedEncodingByDefault: false,
doc-frontend-1          |       sendDate: false,
doc-frontend-1          |       _removedConnection: false,
doc-frontend-1          |       _removedContLen: false,
doc-frontend-1          |       _removedTE: false,
doc-frontend-1          |       strictContentLength: false,
doc-frontend-1          |       _contentLength: 0,
doc-frontend-1          |       _hasBody: true,
doc-frontend-1          |       _trailer: '',
doc-frontend-1          |       finished: true,
doc-frontend-1          |       _headerSent: true,
doc-frontend-1          |       _closed: false,
doc-frontend-1          |       _header: 'GET /language_codes_and_names HTTP/1.1\r\n' +
doc-frontend-1          |         'Accept: application/json, text/plain, */*\r\n' +
doc-frontend-1          |         'User-Agent: axios/1.6.7\r\n' +
doc-frontend-1          |         'Accept-Encoding: gzip, compress, deflate, br\r\n' +
doc-frontend-1          |         'Host: 127.0.0.1:5005\r\n' +
doc-frontend-1          |         'Connection: keep-alive\r\n' +
doc-frontend-1          |         '\r\n',
doc-frontend-1          |       _keepAliveTimeout: 0,
doc-frontend-1          |       _onPendingData: [Function: nop],
doc-frontend-1          |       agent: [Agent],
doc-frontend-1          |       socketPath: undefined,
doc-frontend-1          |       method: 'GET',
doc-frontend-1          |       maxHeaderSize: undefined,
doc-frontend-1          |       insecureHTTPParser: undefined,
doc-frontend-1          |       joinDuplicateHeaders: undefined,
doc-frontend-1          |       path: '/language_codes_and_names',
doc-frontend-1          |       _ended: false,
doc-frontend-1          |       res: null,
doc-frontend-1          |       aborted: false,
doc-frontend-1          |       timeoutCb: [Function: emitRequestTimeout],
doc-frontend-1          |       upgradeOrConnect: false,
doc-frontend-1          |       parser: null,
doc-frontend-1          |       maxHeadersCount: null,
doc-frontend-1          |       reusedSocket: false,
doc-frontend-1          |       host: '127.0.0.1',
doc-frontend-1          |       protocol: 'http:',
doc-frontend-1          |       _redirectable: [Circular *1],
doc-frontend-1          |       [Symbol(shapeMode)]: false,
doc-frontend-1          |       [Symbol(kCapture)]: false,
doc-frontend-1          |       [Symbol(kBytesWritten)]: 0,
doc-frontend-1          |       [Symbol(kNeedDrain)]: false,
doc-frontend-1          |       [Symbol(corked)]: 0,
doc-frontend-1          |       [Symbol(kChunkedBuffer)]: [],
doc-frontend-1          |       [Symbol(kChunkedLength)]: 0,
doc-frontend-1          |       [Symbol(kSocket)]: [Socket],
doc-frontend-1          |       [Symbol(kOutHeaders)]: [Object: null prototype],
doc-frontend-1          |       [Symbol(errored)]: null,
doc-frontend-1          |       [Symbol(kHighWaterMark)]: 16384,
doc-frontend-1          |       [Symbol(kRejectNonStandardBodyWrites)]: false,
doc-frontend-1          |       [Symbol(kUniqueHeaders)]: null
doc-frontend-1          |     },
doc-frontend-1          |     _currentUrl: 'http://127.0.0.1:5005/language_codes_and_names',
doc-frontend-1          |     [Symbol(shapeMode)]: true,
doc-frontend-1          |     [Symbol(kCapture)]: false
doc-frontend-1          |   },
doc-frontend-1          |   cause: Error: connect ECONNREFUSED 127.0.0.1:5005
doc-frontend-1          |       at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1602:16) {
doc-frontend-1          |     errno: -111,
doc-frontend-1          |     code: 'ECONNREFUSED',
doc-frontend-1          |     syscall: 'connect',
doc-frontend-1          |     address: '127.0.0.1',
doc-frontend-1          |     port: 5005
doc-frontend-1          |   }
doc-frontend-1          | }
2

There are 2 best solutions below

0
On BEST ANSWER

It ended up being a problem with the load function in +page.server.ts. This is what worked:

import { PUBLIC_LANG_CODES_NAMES_URL } from '$env/static/public'
import { env } from '$env/dynamic/public'
import type { PageServerLoad } from './$types'

export const load: PageServerLoad = async () => {
  const url = `${env.PUBLIC_BACKEND_API_URL}${PUBLIC_LANG_CODES_NAMES_URL}`
  console.log(`About to fetch ${url}...`)
  const response = await fetch(url)
  const langCodeNameAndTypes: Array<[string, string, boolean]> = await response.json()
  if (!response.ok) {
    throw new Error(response.statusText)
  }
  return { result: langCodeNameAndTypes }
}

The difference that ended up mattering? Making langCodeNameAndTypes keyed via my arbitrary result of the key name result.

N.B. Initially it was suspected that there might be a problem with the config of docker networking in the docker-compose.yml file, but I did check out the docker networking and it was all fine as evidenced by docker exec-ing into each service and verifying by ping and curl -f that communication was working properly as. well as using inspect.

N.B. This code was transitioning from plain Svelte to SvelteKit with a desire to use dynamic private env vars. Above the code uses public dynamic env var, but that can easily be changed by changing the PUBLIC_BACKEND_API_URL to be BACKEND_API_URL both in the code and in the .env file.

1
On

ECONNREFUSED means TCP/IP connection to the given address did not succeed.

It is a low level error from the operating system. Unfortunately, kernel cannot give more information, and it is now up to network tools to figure out why your network does not work.

Try

  • curl
  • telnet

If you are using Docker (as it seems) read

  • Docker tutorials on how to set up network
  • How to debug networking from inside docker containers

Unfortunately for anyone doing this kind of debugging for you is very difficult, because it is a local problem. The best way to solve is to learn how the networking works and have the skills to pin down network problems yourself.