You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Better-Auth 1.3.6/1.3.7中更新用户名时遭遇PG错误:users表的displayUsername列不存在

在Better-Auth 1.3.6/1.3.7中更新用户名时遭遇PG错误:users表的displayUsername列不存在

看起来你遇到的问题是Better-Auth在尝试更新用户信息时,试图操作displayUsername这个驼峰命名的列,但你的PostgreSQL用户表中实际存在的是display_username(蛇形命名)列——PostgreSQL对字段命名是严格区分的,所以才会抛出“列不存在”的错误。

问题根源拆解

从你提供的迁移文件能看到,创建users表时你定义的字段是display_username,但Better-Auth内部生成的更新SQL却在引用displayUsername。这明显是字段命名风格不匹配导致的冲突:Better-Auth默认可能采用驼峰命名生成数据库操作语句,而你的数据库Schema用的是蛇形命名,两者没有对齐。


解决方案

下面提供几种可行的解决思路,按推荐程度排序:

方案一:配置Better-Auth适配蛇形命名字段(最推荐)

在Better-Auth的初始化配置中,指定用户表的字段映射,让它把内部使用的驼峰字段名对应到数据库中的蛇形字段名。针对1.3.x版本,你可以尝试这样配置:

// 你的auth初始化文件(比如src/auth.ts)
import { auth } from "better-auth";

export const { handlers, signIn, signOut, getSession } = auth({
  database: {
    url: process.env.DATABASE_URL, // 你的数据库连接地址
    usersTable: {
      columns: {
        // 将Better-Auth内部的驼峰字段映射到数据库的蛇形字段
        displayUsername: "display_username",
        // 如果还有其他类似冲突的字段,也可以在这里添加映射
        // 比如 emailVerified: "email_verified"
      }
    }
  },
  // 其他Better-Auth配置(如登录 providers、session 配置等)
});

如果你的Better-Auth版本没有usersTable.columns这个配置项,可以查看对应版本的官方文档,关键词可以搜「field mapping」「column aliases」来找到正确的配置方式。

方案二:修改数据库Schema适配驼峰字段

如果你不想调整Better-Auth的配置,也可以修改数据库表结构,让字段名和Better-Auth的期望保持一致:

选项A:重命名现有字段(推荐,无冗余)

创建一个新的迁移文件(比如src/data/migrations/1748xxxxxx_rename-display-username.ts):

import type { MigrationBuilder } from "node-pg-migrate";

export const up = (pgm: MigrationBuilder) => {
  // 将display_username重命名为displayUsername
  pgm.renameColumn("users", "display_username", "displayUsername");
};

export const down = (pgm: MigrationBuilder) => {
  // 回滚操作
  pgm.renameColumn("users", "displayUsername", "display_username");
};

运行迁移命令(比如npm run migrate up)后,数据库字段名就会和Better-Auth的期望匹配。

选项B:添加新驼峰字段并同步数据(不推荐,有冗余)

如果需要保留原有的display_username字段,可以添加新字段并同步现有数据:

import type { MigrationBuilder } from "node-pg-migrate";

export const up = (pgm: MigrationBuilder) => {
  // 添加displayUsername列
  pgm.addColumn("users", "displayUsername", { type: "text" });
  // 同步现有数据到新列
  pgm.sql("UPDATE users SET displayUsername = display_username;");
};

export const down = (pgm: MigrationBuilder) => {
  // 回滚删除新列
  pgm.dropColumn("users", "displayUsername");
};

⚠️ 注意:这种方式会产生冗余字段,后续维护需要同步两个字段的值,所以仅作为临时方案。

方案三:检查Better-Auth的全局命名风格配置

部分Better-Auth版本提供了全局命名风格开关,比如是否自动将驼峰字段转换为蛇形命名。你可以查看1.3.6/1.3.7版本的文档,看看是否有类似snakeCase: true这样的配置项,开启后就能自动适配你的数据库Schema。


你提供的错误信息与迁移文件参考

完整错误信息

SERVER_ERROR: error: column "displayUsername" of relation "users" does not exist
    at /Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/pg/lib/client.js:545:17
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async PostgresConnection.executeQuery (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/dialect/postgres/postgres-driver.js:93:49)
    at async /Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-executor/query-executor-base.js:37:28
    at async DefaultConnectionProvider.provideConnection (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/driver/default-connection-provider.js:12:20)
    at async DefaultQueryExecutor.executeQuery (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-executor/query-executor-base.js:36:16)
    at async UpdateQueryBuilder.execute (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-builder/update-query-builder.js:461:24)
    at async UpdateQueryBuilder.executeTakeFirst (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-builder/update-query-builder.js:477:26)
    at async withReturning (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/better-auth/dist/shared/better-auth.DOgvYMa8.cjs:119:13)
    at async Object.update (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/better-auth/dist/shared/better-auth.DOgvYMa8.cjs:265:16)
    at PostgresConnection.executeQuery (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/dialect/postgres/postgres-driver.js:105:69)
    at process.processTicksAndRejections (node:internal/process/task_queues:105:5)
    at async /Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-executor/query-executor-base.js:37:28
    at async DefaultConnectionProvider.provideConnection (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/driver/default-connection-provider.js:12:20)
    at async DefaultQueryExecutor.executeQuery (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-executor/query-executor-base.js:36:16)
    at async UpdateQueryBuilder.execute (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-builder/update-query-builder.js:461:24)
    at async UpdateQueryBuilder.executeTakeFirst (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/kysely/dist/cjs/query-builder/update-query-builder.js:477:26)
    at async withReturning (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/better-auth/dist/shared/better-auth.DOgvYMa8.cjs:119:13)
    at async Object.update (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/better-auth/dist/shared/better-auth.DOgvYMa8.cjs:265:16)
    at async Object.update (/Users/vr/Desktop/code/ch_NEXT/ch_api/node_modules/better-auth/dist/shared/better-auth.DzBLnNed.cjs:463:19) {
  length: 135,
  severity: 'ERROR',
  code: '42703',
  detail: undefined,
  hint: undefined,
  position: '37',
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'analyze.c',
  line: '2536',
  routine: 'transformUpdateTargetList'
}

迁移文件:1748345325030_create-users-table.ts

import type { MigrationBuilder } from "node-pg-migrate";

export const up = (pgm: MigrationBuilder) => {
  pgm.createTable(
    "users",
    {
      id: { primaryKey: true, type: "uuid" },
      ban_expires: { type: "timestamptz" },
      ban_reason: { type: "text" },
      banned: { type: "boolean" },
      display_username: { type: "text" },
      email: { notNull: true, type: "text" },
      email_verified: { notNull: true, type: "boolean" },
      image: { type: "text" },
      name: { notNull: true, type: "text" },
      role: { type: "text" },
      username: { type: "text" },
      created_at: { notNull: true, type: "timestamptz" },
      updated_at: { notNull: true, type: "timestamptz" },
    },
    { ifNotExists: true }
  );
};

export const down = (pgm: MigrationBuilder) => {
  pgm.dropTable("users", { cascade: true, ifExists: true });
};

迁移文件:1748348413644_add-users-indexes.ts

import type { MigrationBuilder } from "node-pg-migrate";

export const up = (pgm: MigrationBuilder) => {
  pgm.createIndex("users", "email", {
    ifNotExists: true,
    method: "btree",
    name: "users_email_idx",
    unique: true,
  });
  pgm.createIndex("users", "username", {
    ifNotExists: true,
    method: "btree",
    name: "users_username_idx",
    unique: true,
  });
};

export const down = (pgm: MigrationBuilder) => {
  pgm.dropIndex("users", "username", {
    cascade: true,
    ifExists: true,
    name: "users_username_idx",
  });
  // 建议补充删除email索引的回滚操作
  // pgm.dropIndex("users", "email", {
  //   cascade: true,
  //   ifExists: true,
  //   name: "users_email_idx",
  // });
};

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.07 07:34:32