neondatabase / serverless

Connect to Neon PostgreSQL from serverless/worker/edge functions
https://www.npmjs.com/package/@neondatabase/serverless
MIT License
321 stars 13 forks source link

InvalidArgumentError: invalid upgrade header #7

Closed bbigras closed 1 year ago

bbigras commented 1 year ago

Steps to reproduce

Is the connection string the right URL? invalid upgrade header sounds like a websocket error, so I'm wondering if I was supposed to use the connection string or maybe a URL for the proxy.

Expected result

Actual result

node:internal/deps/undici/undici:14152
    Error.captureStackTrace(err, this);
          ^

TypeError: fetch failed
    at Object.fetch (node:internal/deps/undici/undici:14152:11) {
  cause: InvalidArgumentError: invalid upgrade header
      at processHeader (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/core/request.js:352:11)
      at new Request (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/core/request.js:162:9)
      at [dispatch] (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/client.js:280:21)
      at Intercept (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/interceptor/redirectInterceptor.js:11:16)
      at [Intercepted Dispatch] (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/dispatcher-base.js:157:12)
      at Client.dispatch (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/dispatcher-base.js:178:40)
      at [dispatch] (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/pool-base.js:143:28)
      at [Intercepted Dispatch] (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/dispatcher-base.js:149:29)
      at Pool.dispatch (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/dispatcher-base.js:178:40)
      at [dispatch] (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/agent.js:118:23)
      at Intercept (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/interceptor/redirectInterceptor.js:11:16)
      at [Intercepted Dispatch] (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/dispatcher-base.js:157:12)
      at Agent.dispatch (/home/bbigras/dev/test-qwik-neon/node_modules/undici/lib/dispatcher-base.js:178:40)
      at node:internal/deps/undici/undici:14046:83
      at new Promise (<anonymous>)
      at dispatch (node:internal/deps/undici/undici:14046:16)
      at httpNetworkFetch (node:internal/deps/undici/undici:13954:65)
      at httpNetworkOrCacheFetch (node:internal/deps/undici/undici:13856:39)
      at httpFetch (node:internal/deps/undici/undici:13705:43)
      at schemeFetch (node:internal/deps/undici/undici:13633:24)
      at node:internal/deps/undici/undici:13509:26
      at mainFetch (node:internal/deps/undici/undici:13526:11)
      at fetching (node:internal/deps/undici/undici:13483:7)
      at fetch2 (node:internal/deps/undici/undici:13361:20)
      at Object.fetch (node:internal/deps/undici/undici:14150:18)
      at fetch (node:internal/process/pre_execution:237:25)
      at ws (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:2810)
      at new Promise (<anonymous>)
      at G.connect (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:2505)
      at hn.connect (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:19336)
      at jt._connect (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:23419)
      at /home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:24102
      at new Promise (<anonymous>)
      at jt.connect (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:24071)
      at jt.connect (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:45697)
      at routes_component_xYL1qOwPyDI (/src/routes_component_xyl1qowpydi.js:9:18)
      at invoke (file:///home/bbigras/dev/test-qwik-neon/node_modules/@builder.io/qwik/core.mjs:707:26)
      at file:///home/bbigras/dev/test-qwik-neon/node_modules/@builder.io/qwik/core.mjs:6618:28
      at async Promise.all (index 0)
      at async Promise.all (index 0)
      at async renderRoot (file:///home/bbigras/dev/test-qwik-neon/node_modules/@builder.io/qwik/core.mjs:7902:5)
      at async _renderSSR (file:///home/bbigras/dev/test-qwik-neon/node_modules/@builder.io/qwik/core.mjs:7898:5)
      at async Proxy.renderToStream (file:///home/bbigras/dev/test-qwik-neon/node_modules/@builder.io/qwik/server.mjs:642:3)
      at async /home/bbigras/dev/test-qwik-neon/node_modules/@builder.io/qwik/optimizer.cjs:1767:28 {
    code: 'UND_ERR_INVALID_ARG'
  }
}

Node.js v18.14.0

Environment

npm: '9.3.1', node: '18.14.0'

Logs, links

marbemac commented 1 year ago

➕ We are evaluating cloudflare + neon, and are also seeing this issue. Even taking cloudflare out of the mix, and just running a file along the lines below, results in the error (this is on node 18):

// @ts-expect-error no types
import { Client } from '@neondatabase/serverless';

const client = new Client('postgres://{USER}:{PASS}@{ENDPOINT}.us-east-2.aws.neon.tech/{DB}');
await client.connect();
const {
  rows: [{ now }],
} = await client.query('select now();');

console.log('NOW!', now);

Any ideas?

marbemac commented 1 year ago

Ok, in a node environment it seems one has to manually set neonConfig.webSocketConstructor to the ws library, along these lines:

// @ts-expect-error no types
import { Client, neonConfig } from '@neondatabase/serverless';
import ws from 'ws';

neonConfig.webSocketConstructor = ws;

const client = new Client('postgres://{USER}:{PASS}@{ENDPOINT}.us-east-2.aws.neon.tech/{DB}');
await client.connect();
const {
  rows: [{ now }],
} = await client.query('select now();');

console.log('NOW!', now);
jawj commented 1 year ago

Right, you get 'invalid upgrade header' if no WebSocket object is available, because then we try the Cloudflare method where you add that header to an ordinary fetch call.

As you've discovered, you can fix this in Node (and possibly elsewhere) by manually supplying a WebSocket constructor function, such as provided by the ws library.

This is new and a bit experimental, which is why it's not documented yet. I'm actually looking now at whether we can skip the config and just use ws automatically if the package is installed. And to provide a more informative error message if not!

jawj commented 1 year ago

@bbigras Does the above suggestion (using webSocketConstructor) fix things for you too?

bbigras commented 1 year ago

YES IT WORKS!!! :tada: Thank you both so much!!!

Note that if you forget to specify the password in the URL, you get:

TypeError: ji.join is not a function
    at ve.exports.getFileName (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:2:308)
    at Ar.exports (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:2:2063)
    at jt._checkPgPass (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:25699)
    at jt._handleAuthCleartextPassword (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:25840)
    at hn.<anonymous> (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:46157)
    at M.emit (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:1:30872)
    at G.<anonymous> (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:19460)
    at Object.Jo (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:1:31814)
    at M.emit (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:1:30813)
    at G.connect (/home/bbigras/dev/test-qwik-neon/node_modules/@neondatabase/serverless/index.js:43:3222)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
jawj commented 1 year ago

Thanks — with the latest version you should get a more helpful error message if you forget to include the password.