运行seeder脚本报错SCRAM-SERVER-FIRST-MESSAGE: client password must be a string
报错原因
- 该报错的本质是执行seeder脚本时,
process.env.DBPASS取值为undefined,PostgreSQL客户端要求密码必须为字符串类型,因此抛出类型错误。 - 启动服务正常但seeder脚本报错的核心原因是
dotenv的加载路径受执行命令的工作目录影响:- 运行
npm run server时,npm默认将工作目录设置为项目根目录(和.env文件同目录),db.js中的dotenv.config()可以正常读取到环境变量。 - 执行seeder脚本时如果工作目录不是项目根目录,
dotenv.config()会找不到.env文件,导致DBPASS变量未定义。
- 运行
- 少数情况由ES模块导入顺序导致:seeder脚本中
connectDB的导入语句会早于dotenv.config()执行,但因为db.js中也配置了dotenv加载,该问题出现概率较低。
排查验证
你可以先查看seeder脚本中console.log(process.env.DBPASS)的输出,如果结果为undefined,即可确认是.env文件未被正常加载。
修复方案
方案1:指定dotenv加载的绝对路径(最稳妥)
修改db.js中的dotenv配置,明确绑定.env文件的绝对路径,不受执行目录影响:
import dotenv from "dotenv"; import path from "path"; import { fileURLToPath } from "url"; // 适配ES模块获取当前文件路径 const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); // 假设.env在项目根目录,db.js存放在/config目录下,../表示返回上一级到根目录 dotenv.config({ path: path.resolve(__dirname, '../.env') });
根据你的实际目录结构调整path.resolve的参数,保证路径指向项目根目录的.env文件即可。
方案2:添加类型兜底避免报错
在Sequelize初始化时对密码参数添加兜底逻辑,就算环境变量加载失败也不会触发类型错误,方便后续排查:
const sequelize = new Sequelize(database, user, process.env.DBPASS ?? '', { host, port, dialect: "postgres", logging: false, });
方案3:调整seeder的执行方式
执行seeder脚本时,保持工作目录为项目根目录,直接从根目录调用脚本即可:
# 假如seeder.js在根目录 node seeder.js # 假如seeder.js在scripts子目录 node scripts/seeder.js
不要进入seeder脚本所在的子目录再执行命令,否则dotenv会找不到根目录的.env文件。
内容的提问来源于stack exchange,提问作者Austin Howard
相关产品推荐
相关产品推荐

