next-learn: Chapter 6: Getting error while seeding data for customer

Error seeding customers: NeonDbError: db error: ERROR: prepared statement “s416330” does not exist

$ node -r dotenv/config ./scripts/seed.js
Created "users" table
Seeded 1 users
Created "customers" table
Error seeding customers: NeonDbError: db error: ERROR: prepared statement "s416330" does not exist

Caused by:
    ERROR: prepared statement "s416330" does not exist
    at execute (/Users/everythingapple/Desktop/iNoor/React/Next/nextjs-dashboard/node_modules/@neondatabase/serverless/index.js:1539:48)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.all (index 5)
    at async seedCustomers (/Users/everythingapple/Desktop/iNoor/React/Next/nextjs-dashboard/scripts/seed.js:106:31)
    at async /Users/everythingapple/Desktop/iNoor/React/Next/nextjs-dashboard/scripts/seed.js:165:3 {
  code: '26000',
  sourceError: undefined
}
node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

NeonDbError: db error: ERROR: prepared statement "s416330" does not exist

Caused by:
    ERROR: prepared statement "s416330" does not exist
    at execute (/Users/everythingapple/Desktop/iNoor/React/Next/nextjs-dashboard/node_modules/@neondatabase/serverless/index.js:1539:48)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async Promise.all (index 5)
    at async seedCustomers (/Users/everythingapple/Desktop/iNoor/React/Next/nextjs-dashboard/scripts/seed.js:106:31)
    at async /Users/everythingapple/Desktop/iNoor/React/Next/nextjs-dashboard/scripts/seed.js:165:3 {
  code: '26000',
  sourceError: undefined
}

this error is coming somewhere in the following code

const { sql } = require('@vercel/postgres');
const {
  invoices,
  customers,
  revenue,
  users,
} = require('../app/lib/placeholder-data.js');
const bcrypt = require('bcrypt');

........
 // Insert data into the "customers" table
    const insertedCustomers = await Promise.all(
      customers.map(
        (customer) => sql`
        INSERT INTO customers (id, name, email, image_url)
        VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
        ON CONFLICT (id) DO NOTHING;
      `,
      ),
    );

@vercel/postgres”: “^0.5.0” “bcrypt”: “^5.1.1”, “next”: “^14.0.0”, Node : 18.18.2

About this issue

  • Original URL
  • State: closed
  • Created 8 months ago
  • Reactions: 6
  • Comments: 30 (8 by maintainers)

Most upvoted comments

Here’s the fix: https://github.com/vercel/next-learn/pull/314

I believe the problem was with the fact sql opens a new db connection whenever it’s called.

@Maniload was on the right track in the sense that using a for loop would open the connections sequentially, whereas Promise.all initiates the promises in parallel - creating multiple connections at once.

However, with the loop, we’re still creating multiple connections. The ideal solution is to run the script on a single connection, and we can use db.client for that. More details on the PR.

Please let me know if you run into any more issues (and remember to drop your tables on Vercel before testing again) 😄

Hey 👋🏼 I was able to reproduce this with a fresh project. Looking into it.

Maybe this is caused by a multiple INSERTs being executed concurrently? It seems to work better when I convert the Promise.all calls to simple for-loops:

// Insert data into the "invoices" table
const insertedInvoices = [];
for (const invoice of invoices) {
  insertedInvoices.push(await sql`
    INSERT INTO invoices (customer_id, amount, status, date)
    VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
    ON CONFLICT (id) DO NOTHING;
  `);
}

can you send seed.js file code

const { sql } = require('@vercel/postgres');
const {
  invoices,
  customers,
  revenue,
  users,
} = require('../app/lib/placeholder-data.js');
const bcrypt = require('bcrypt');

async function seedUsers() {
  try {
    await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;
    // Create the "invoices" table if it doesn't exist
    const createTable = await sql`
      CREATE TABLE IF NOT EXISTS users (
        id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        email TEXT NOT NULL UNIQUE,
        password TEXT NOT NULL
      );
    `;

    console.log(`Created "users" table`);

    // Insert data into the "users" table
    const insertedUsers = await Promise.all(
      users.map(async (user) => {
        const hashedPassword = await bcrypt.hash(user.password, 10);
        return sql`
        INSERT INTO users (id, name, email, password)
        VALUES (${user.id}, ${user.name}, ${user.email}, ${hashedPassword})
        ON CONFLICT (id) DO NOTHING;
      `;
      }),
    );

    console.log(`Seeded ${insertedUsers.length} users`);

    return {
      createTable,
      users: insertedUsers,
    };
  } catch (error) {
    console.error('Error seeding users:', error);
    throw error;
  }
}

async function seedInvoices() {
  try {
    await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;

    // Create the "invoices" table if it doesn't exist
    const createTable = await sql`
    CREATE TABLE IF NOT EXISTS invoices (
    id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    customer_id UUID NOT NULL,
    amount INT NOT NULL,
    status VARCHAR(255) NOT NULL,
    date DATE NOT NULL
  );
`;

    console.log(`Created "invoices" table`);

    // Insert data into the "invoices" table
    const insertedInvoices = await Promise.all(
      invoices.map(
        (invoice) => sql`
        INSERT INTO invoices (customer_id, amount, status, date)
        VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
        ON CONFLICT (id) DO NOTHING;
      `,
      ),
    );

    console.log(`Seeded ${insertedInvoices.length} invoices`);

    return {
      createTable,
      invoices: insertedInvoices,
    };
  } catch (error) {
    console.error('Error seeding invoices:', error);
    throw error;
  }
}

async function seedCustomers() {
  try {
    await sql`CREATE EXTENSION IF NOT EXISTS "uuid-ossp"`;

    // Create the "customers" table if it doesn't exist
    const createTable = await sql`
      CREATE TABLE IF NOT EXISTS customers (
        id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
        name VARCHAR(255) NOT NULL,
        email VARCHAR(255) NOT NULL,
        image_url VARCHAR(255) NOT NULL
      );
    `;

    console.log(`Created "customers" table`);

    // Insert data into the "customers" table
    const insertedCustomers = await Promise.all(
      customers.map(
        (customer) => sql`
        INSERT INTO customers (id, name, email, image_url)
        VALUES (${customer.id}, ${customer.name}, ${customer.email}, ${customer.image_url})
        ON CONFLICT (id) DO NOTHING;
      `,
      ),
    );

    console.log(`Seeded ${insertedCustomers.length} customers`);

    return {
      createTable,
      customers: insertedCustomers,
    };
  } catch (error) {
    console.error('Error seeding customers:', error);
    throw error;
  }
}

async function seedRevenue() {
  try {
    // Create the "revenue" table if it doesn't exist
    const createTable = await sql`
      CREATE TABLE IF NOT EXISTS revenue (
        month VARCHAR(4) NOT NULL UNIQUE,
        revenue INT NOT NULL
      );
    `;

    console.log(`Created "revenue" table`);

    // Insert data into the "revenue" table
    const insertedRevenue = await Promise.all(
      revenue.map(
        (rev) => sql`
        INSERT INTO revenue (month, revenue)
        VALUES (${rev.month}, ${rev.revenue})
        ON CONFLICT (month) DO NOTHING;
      `,
      ),
    );

    console.log(`Seeded ${insertedRevenue.length} revenue`);

    return {
      createTable,
      revenue: insertedRevenue,
    };
  } catch (error) {
    console.error('Error seeding revenue:', error);
    throw error;
  }
}

(async () => {
  await seedUsers();
  await seedCustomers();
  await seedInvoices();
  await seedRevenue();
})();

Yes using pool is best way as its create a single connection.

Maybe this is caused by a multiple INSERTs being executed concurrently? It seems to work better when I convert the Promise.all calls to simple for-loops:

// Insert data into the "invoices" table
const insertedInvoices = [];
for (const invoice of invoices) {
  insertedInvoices.push(await sql`
    INSERT INTO invoices (customer_id, amount, status, date)
    VALUES (${invoice.customer_id}, ${invoice.amount}, ${invoice.status}, ${invoice.date})
    ON CONFLICT (id) DO NOTHING;
  `);
}

It works, thanks!