sidorares/node-mysql2 · error · Error
"database" connection config property must be a string
Error message
"database" connection config property must be a string
What it means
Sibling of the `user` guard, thrown by HandshakeResponse.toPacket() when serializing the database name into the handshake packet (only when CONNECT_WITH_DB is negotiated). The constructor's this.database = handshake.database || '' only coerces falsy values, so a truthy non-string survives to this typeof check and aborts the handshake mid-connect.
Solutions
- Cast the value to a string: database: String(opts.database).
- Validate the config object with a schema (zod, joi) before connecting.
- Correct the upstream source so `database` is always a string.
Example fix
// before
createConnection({ host: 'localhost', database: 123 });
// after
createConnection({ host: 'localhost', database: '123' }); Defensive patterns
Strategy: type-guard
Validate before calling
function normalizeConnectionConfig(opts) {
if ('database' in opts && opts.database != null && typeof opts.database !== 'string') {
opts = { ...opts, database: String(opts.database) };
}
return opts;
}
const safeOpts = normalizeConnectionConfig(rawOpts);
const conn = await createConnection(safeOpts); Type guard
function isValidDatabase(opt) {
return opt == null || typeof opt === 'string';
}
if (!isValidDatabase(opts.database)) {
throw new TypeError(`database must be a string, got ${typeof opts.database}`);
} Prevention
- Validate the config schema before connecting; fail at startup, not during the handshake.
- Quote numeric database names in JSON/YAML to keep them strings.
- Double-check field placement in config builders (port vs database).
When it happens
Trigger: Passing a truthy non-string as `database`: createConnection({ database: 3306 }) (port value misplaced), createPool({ database: ['app'] }), or a value loaded from a schema where the field was typed as a number/object.
Common situations: Config typos putting a port or pool size into the database field; YAML/JSON where an unquoted numeric database name parses as a number; ORM migrations that construct config objects programmatically with the wrong field.
Related errors
- "user" connection config property must be a string
- Bind parameters must be array if namedPlaceholders…
- Bind parameters must not contain function(s). To pass the…
- Bind parameters must not contain undefined
- Bind parameters must not contain undefined. To pass SQL…
AI-assisted analysis of sidorares/node-mysql2@8b1f829d37 (2026-08-11).
Data as JSON: /api/errors/3385e4b62e8c8153.
Report an issue: GitHub.
Appendix: source
Thrown at lib/packets/handshake_response.js:129
}
packet.writeLengthCodedNumber(keysLength);
for (k = 0; k < attrNames.length; ++k) {
packet.writeLengthCodedString(attrNames[k], encoding);
packet.writeLengthCodedString(
connectAttributes[attrNames[k]],
encoding
);
}
}
return packet;
}
toPacket() {
if (typeof this.user !== 'string') {
throw new Error('"user" connection config property must be a string');
}
if (typeof this.database !== 'string') {
throw new Error('"database" connection config property must be a string');
}
// dry run: calculate resulting packet length
const p = this.serializeResponse(Packet.MockBuffer());
return this.serializeResponse(Buffer.alloc(p.offset));
}
static fromPacket(packet, serverFlags = 0xffffffff) {
const args = {};
args.clientFlags = packet.readInt32();
function isSet(flag) {
return args.clientFlags & serverFlags & ClientConstants[flag];
}
args.maxPacketSize = packet.readInt32();
args.charsetNumber = packet.readInt8();
const encoding = CharsetToEncoding[args.charsetNumber];
args.encoding = encoding;
packet.skip(23);
args.user = packet.readNullTerminatedString(encoding);
let authTokenLength;View on GitHub (pinned to 8b1f829d37)