porsager / postgres

Postgres.js - The Fastest full featured PostgreSQL client for Node.js, Deno, Bun and CloudFlare
The Unlicense
7.39k stars 267 forks source link

Deno - error: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'replace') #778

Open bidipeppercrap opened 8 months ago

bidipeppercrap commented 8 months ago

image image

Spec

Runtime: Deno Database Provider: Neon

Reproduce:

I run into this error when I try to migrate.

Code

deno.json

{
    "imports": {
        "db/": "./src/db/",
        "kysely": "npm:kysely@^0.27.2",
        "kysely-postgres-js": "npm:kysely-postgres-js@^2.0.0",
        "postgres": "https://deno.land/x/postgresjs@v3.4.3/mod.js"
    },
    "tasks": {
        "migrate": "deno run -A ./src/db/migrator.ts"
    }
}

migrator:

import * as path from "node:path";
import { fileURLToPath } from "node:url";
import { promises as fs } from "node:fs";
import { Migrator, FileMigrationProvider } from "kysely";
import { db } from "db/database.ts";

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

async function migrateToLatest() {
    const migrator = new Migrator({
        db,
        provider: new FileMigrationProvider({
            fs,
            path,
            migrationFolder: path.join(__dirname, "./migrations")
        })
    });

    const { error, results } = await migrator.migrateToLatest();

    results?.forEach((it) => {
        if (it.status === "Success") {
            console.log(`migration "${it.migrationName}" was executed successfully`);
        } else if (it.status === "Error") {
            console.error(`failed to execute migration "${it.migrationName}"`);
        }
    });

    if (error) {
        console.error("failed to migrate");
        console.error(error);
        Deno.exit(1);
    }

    await db.destroy();
}

migrateToLatest();

db instance:

import { Database } from "db/types/index.ts";
import postgres from "postgres";
import { Kysely } from "kysely";
import { PostgresJSDialect } from "kysely-postgres-js";
import { load } from "https://deno.land/std@0.212.0/dotenv/mod.ts";

const env = await load();

const dialect = new PostgresJSDialect({
    postgres: postgres({
        database: env["PGDATABASE"]!,
        host: env["PGHOST"]!,
        user: env["PGUSER"]!,
        password: env["PGPASSWORD"]!,
        port: 5434,
        max: 10,
    })
});

export const db = new Kysely<Database>({
    dialect
});
skelawsky commented 7 months ago

Have you found solution?

lpite commented 7 months ago

Same problem with nextjs node or bun doesn't matter

bidipeppercrap commented 7 months ago

Same problem with nextjs node or bun doesn't matter

I found it worked with Node

Only in Deno it is not working.

lpite commented 7 months ago

Same problem with nextjs node or bun doesn't matter

I found it worked with Next.js Typescript

Only in Deno it is not working.

It's working in production I guess but on dev it can work for a while but then on hot reload this error happens

bidipeppercrap commented 7 months ago

Same problem with nextjs node or bun doesn't matter

I found it worked with Next.js Typescript Only in Deno it is not working.

It's working in production I guess but on dev it can work for a while but then on hot reload this error happens

This is a matter of migrating It worked with Node or npm run migrate... But doesn't work with deno task migrate...

divmgl commented 7 months ago

I'm having this issue when reserving but not with regular connections. @porsager could really use your help here.

const admin = pg(databaseUrl, { database: "postgres" })

return {
  admin: await admin.reserve()
}

Crashes:

node_modules/.pnpm/postgres@3.4.3/node_modules/postgres/src/connection.js:389
      stack: { value: err.stack + query.origin.replace(/.*\n/, '\n'), enumerable: options.debug },
                                               ^

TypeError: Cannot read properties of undefined (reading 'replace')

Heads up that doing

await admin.unsafe("SELECT 1")

Solved the issue for me.

episage commented 7 months ago

The problem occurs when I open my Mac after a couple of hours. This is a bug in error handling routine and obscures the real error. 100% should be fixed in this package.

file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:389
      stack: { value: err.stack + query.origin.replace(/.*\n/, '\n'), enumerable: options.debug },
                                               ^

TypeError: Cannot read properties of undefined (reading 'replace')
    at queryError (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:389:48)
    at errored (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:383:14)
    at Socket.data (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:318:9)
    at Socket.emit (node:events:514:28)
    at Socket.emit (node:domain:488:12)
    at addChunk (node:internal/streams/readable:376:12)
    at readableAddChunk (node:internal/streams/readable:349:9)
    at Readable.push (node:internal/streams/readable:286:10)
    at TCP.onStreamRead (node:internal/stream_base_commons:190:23)

Node.js v20.9.0
npm ERR! Lifecycle script `dev` failed with error: 
npm ERR! Error: command failed 
npm ERR!   in workspace: backend@1.0.0 
npm ERR!   at location: /Users/epi/projects/hs4/packages/backend 
episage commented 6 months ago

Found the offending line:

image
Query:
{
  reserve: [Function (anonymous)],
  state: { pid: 17618, secret: 131674580 },
  active: true
}
Error:
TypeError: Cannot read properties of undefined (reading '0')
    at build (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:223:42)
    at execute (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:167:7)
    at ReadyForQuery (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:568:27)
    at handle (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:503:6)
    at Socket.data (file:///Users/epi/projects/hs4/node_modules/postgres/src/connection.js:315:9)
    at Socket.emit (node:events:514:28)
    at Socket.emit (node:domain:488:12)
    at addChunk (node:internal/streams/readable:376:12)
    at readableAddChunk (node:internal/streams/readable:349:9)
    at Readable.push (node:internal/streams/readable:286:10)
coder-se commented 4 months ago

We saw this issue as well in our production environments after starting to use kysely-postgres-js.

We managed to track it down to the fact that initial is sometimes set to true and sometime to a query, it also seems to be true more frequently when reserving connections using reserve(). This is what kysely-postgres-js does under the hood, and also when @divmgl saw it. The current "workaround" is to use the suggestion from @divmgl and add a await sql.unsafe('SELECT 1') before the connection is reserved. By doing this we get the actual error message.

The minimal code to reproduce this issue is to run the code below while your postgres instance is shutting down;

    const sql = postgres({
        ...
    });
    const reserved = await sql.reserve();
    await reserved.unsafe('SELECT 1');

initial could potentially be set to true here; https://github.com/porsager/postgres/blob/f58cd4f3affd3e8ce8f53e42799672d86cd2c70b/src/connection.js#L108-L114

But expected to be a query here; https://github.com/porsager/postgres/blob/f58cd4f3affd3e8ce8f53e42799672d86cd2c70b/src/connection.js#L384-L397

When running the reproduction code above, we could see that query=true in queryError(query, err) { ... }

episage commented 3 months ago

To replicate the problem:

  1. Turn off your SQL server.
  2. Use .reserve().

The error is shadowed with another one throwing in postgres/src/connection.js because query is true instead of actual query.

 + query.origin.replace(/.*\n/, '\n')
image