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 | }
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.