Error: connect ECONNREFUSED ::1:3306This is a common issue on macOS where localhost resolves to IPv6 ::1, but MySQL is only listening on 127.0.0.1.
Solution: Update MySQL config to also bind to IPv6:
# /usr/local/etc/my.cnf (Homebrew MySQL)
[mysqld]
-bind-address = 127.0.0.1
+bind-address = 127.0.0.1,::1
Then restart MySQL:
brew services mysql restart
Alternatively, use 127.0.0.1 instead of localhost in your connection config:
const realm = new Realm({
host: '127.0.0.1', // Use IP instead of 'localhost'
database: 'my_app',
});
Error: connected alreadyThis error occurs when calling connect() multiple times with the default Bone class.
Solution: Either:
connect() only once in your application lifecycleRealm instances with subclass: true for multiple connections// Wrong: calling connect twice
await connect({ models: [Post], database: 'db1' });
await connect({ models: [User], database: 'db2' }); // Error!
// Correct: use separate Realm instances
const realm1 = new Realm({ models: [Post], database: 'db1', subclass: true });
const realm2 = new Realm({ models: [User], database: 'db2', subclass: true });
await realm1.connect();
await realm2.connect();
Error: DriverClass must be a subclass of AbstractDriverThis usually occurs when using BaseRealm directly instead of the full Realm class, or when the dialect option doesn’t match an available driver.
Solution: Ensure you’re importing Realm from leoric (not BaseRealm) and have the correct database client installed:
# For MySQL
npm install mysql2
# For PostgreSQL
npm install pg
# For SQLite
npm install sqlite3
Error: Model is not paranoidThis error occurs when calling restore() on a model that doesn’t have soft delete enabled.
Solution: Add a deletedAt attribute to your model. See Soft Delete.
By default, Leoric maps snake_case column names to camelCase attributes. If your column names don’t follow this convention, use the name option:
@Column({ name: 'gmt_create' })
createdAt: Date;
createdAt / updatedAt not auto-updatingLeoric automatically manages createdAt and updatedAt timestamps if the corresponding columns exist. Ensure your table has created_at and updated_at columns.
To suppress automatic timestamp updates for a specific operation, pass { silent: true }:
await post.update({ title: 'Updated' }, { silent: true });
If you’re not seeing records you expect, they may be soft-deleted. Use .unscoped to include all records:
// This excludes soft-deleted records
const posts = await Post.find();
// This includes all records
const allPosts = await Post.unscoped.find();
If you’re loading associations in a loop, you likely have an N+1 problem:
// Bad: N+1 queries
const posts = await Post.find();
for (const post of posts) {
const comments = await Comment.find({ postId: post.id }); // N queries!
}
// Good: eager loading
const posts = await Post.find().with('comments'); // 1 query with JOIN
See Best Practices for more details.
Leoric uses the debug module. Enable SQL logging with:
DEBUG=leoric node app.js
You can provide a custom logger to see all queries:
const realm = new Realm({
logger: {
logQuery(sql, duration) {
console.log(`[${duration}ms] ${sql}`);
},
logQueryError(err, sql, duration) {
console.error(`[${duration}ms] ${sql}\n Error: ${err.message}`);
},
logMigration(name) {
console.log(`Migration: ${name}`);
},
},
});
See Logging for more details.
emitDecoratorMetadata errorIf decorator type inference is not working, ensure your tsconfig.json has:
{
"compilerOptions": {
"experimentalDecorators": true,
"emitDecoratorMetadata": true
}
}
bigintJavaScript’s bigint type requires special handling. If you encounter type errors:
// Correct: use bigint type
@Column({ primaryKey: true })
id: bigint;
// When creating, bigint literals use 'n' suffix
const post = await Post.create({ title: 'Hello' });
console.log(typeof post.id); // 'bigint' or 'number' depending on value
When running realm.sync(), if a table already exists and you want to update it:
// Alter existing tables (add new columns, etc.)
await realm.sync({ alter: true });
// WARNING: Drop and recreate (data loss!)
await realm.sync({ force: true });
If a migration fails partway, you may need to manually rollback:
module.exports = {
async up(driver, DataTypes) {
// forward migration
},
async down(driver, DataTypes) {
// rollback migration - make sure this is complete
},
};