Troubleshooting
Quick solutions for common issues when working with CQL.
Setup & Installation Issues
Shard Installation Fails
Error: Failed to resolve dependencies
Solution:
- Check Crystal version compatibility: - crystal --version
- Update - shard.ymlwith compatible version:- dependencies: cql: github: azutoolkit/cql version: "~> 1.0"
- Install with: - shards install
Database Driver Not Found
Error: can't load file 'pg'
Solution: Add the database driver to shard.yml:
dependencies:
  # PostgreSQL
  pg:
    github: will/crystal-pg
  # MySQL
  mysql:
    github: crystal-lang/crystal-mysql
  # SQLite
  sqlite3:
    github: crystal-lang/crystal-sqlite3Database Connection Problems
Connection Refused
Error: Connection refused (Errno)
Solutions:
- Verify database is running: - # PostgreSQL pg_isready -h localhost -p 5432 # MySQL mysqladmin ping -h localhost
- Check connection string format: - # Correct "postgres://username:password@localhost:5432/database" "mysql://username:password@localhost:3306/database" "sqlite3:///path/to/database.db"
- Test connection manually: - begin DB.open("postgres://user:pass@localhost/dbname") do |db| result = db.scalar("SELECT 1") puts "Connection successful: #{result}" end rescue ex puts "Connection failed: #{ex.message}" end
Authentication Failed
Error: password authentication failed
Solutions:
- Test credentials manually: - psql -h localhost -U username -d database_name mysql -h localhost -u username -p database_name
- Use environment variables: - uri: ENV["DATABASE_URL"]? || "postgres://localhost:5432/myapp_dev"
- Create database user if needed: - -- PostgreSQL CREATE USER myapp_user WITH PASSWORD 'password'; GRANT ALL PRIVILEGES ON DATABASE myapp_dev TO myapp_user; -- MySQL CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'password'; GRANT ALL PRIVILEGES ON myapp_dev.* TO 'myapp_user'@'localhost';
Schema & Migration Issues
Column Not Found Error
Error: undefined method 'name' for #<NamedTuple(id: Int64)>
Solution: Ensure schema matches database:
# Complete schema definition
table :users do
  primary :id, Int64
  column :name, String
  column :email, String
  timestamps
endVerify with: crystal run db/migrate.cr
Migration Fails - Column Exists
Error: column "email" already exists
Solution: Check before adding columns:
class AddEmailToUsers < CQL::Migration
  def up
    unless column_exists?(:users, :email)
      alter_table :users do
        add_column :email, String
      end
    end
  end
endQuery & Model Issues
Type Mismatch Errors
Error: no overload matches 'User#new'
Solution: Use proper type casting:
# Safe casting
user = User.new(
  name: params["name"]?.try(&.as(String)) || "",
  email: params["email"]?.try(&.as(String)) || "",
  age: params["age"]?.try(&.as(String).to_i?) || 0
)Records Not Found
Error: DB::NoResultsError
# ❌ Missing column
table :users do
  primary :id, Int64
  # Missing: column :name, String
end
# ✅ Complete definition
table :users do
  primary :id, Int64
  column :name, String
  column :email, String
  timestamps
end- Check if migration was run: - # Run pending migrations crystal run db/migrate.cr
- Verify table structure: - -- PostgreSQL \d users -- MySQL DESCRIBE users; -- SQLite .schema users
❌ Issue: Migration Fails with Column Already Exists
Error: PQ::PQError: ERROR: column "email" of relation "users" already existsSolutions:
- Check existing columns before adding: - # In migration alter_table :users do add_column :email, String unless column_exists?(:email) end
- Use conditional migrations: - class AddEmailToUsers < CQL::Migration def up unless column_exists?(:users, :email) alter_table :users do add_column :email, String end end end def down if column_exists?(:users, :email) alter_table :users do drop_column :email end end end end
- Reset and rebuild database (development only): - # ⚠️ This will destroy all data! crystal run db/drop.cr crystal run db/create.cr crystal run db/migrate.cr
🔍 Query & Model Issues
❌ Issue: Type Mismatch Errors
Error: no overload matches 'User#new' with type Hash(String, DB::Any)Solution:
- Ensure proper type casting: - # ❌ Wrong type handling user = User.new(params) # params might have wrong types # ✅ Proper type casting user = User.new( name: params["name"].as(String), email: params["email"].as(String), age: params["age"].as(String).to_i )
- Use safe casting with validation: - # ✅ Safe casting def create_user(params) user = User.new( name: params["name"]?.try(&.as(String)) || "", email: params["email"]?.try(&.as(String)) || "", age: params["age"]?.try(&.as(String).to_i?) || 0 ) # Validate before saving if user.valid? user.save! else puts "Validation errors: #{user.errors.full_messages}" end end
❌ Issue: Records Not Found
Error: DB::NoResultsErrorDebugging Steps:
- Use safe find methods: - # ❌ Unsafe - raises if not found user = User.find!(id) # ✅ Safe - returns nil if not found user = User.find(id) if user puts "Found: #{user.name}" else puts "User not found with ID: #{id}" end
- Check your query conditions: - # Debug your queries query = User.where(email: email) puts "SQL: #{query.to_sql}" # See the generated SQL result = query.first puts result ? "Found user" : "No user found"
- Verify data exists: - # Check if any data exists total_users = User.count puts "Total users in database: #{total_users}" # List all users (for debugging) User.all.each_with_index do |user, i| puts "#{i + 1}. #{user.name} (#{user.email})" end
❌ Issue: Association Loading Problems
Error: undefined method 'posts' for UserSolution:
- Verify association is defined: - struct User include CQL::ActiveRecord::Model(Int64) db_context UserDB, :users # ✅ Define the association has_many :posts, Post, foreign_key: :user_id property id : Int64? property name : String property email : String end
- Check foreign key setup: - struct Post include CQL::ActiveRecord::Model(Int64) db_context UserDB, :posts # ✅ Make sure foreign key column exists property user_id : Int64? property title : String property content : String belongs_to :user, User end
⚠️ Runtime Errors
❌ Issue: Validation Errors Not Displayed
user = User.new(name: "", email: "invalid")
user.save  # Returns false but no error details shownSolution:
- Always check validation errors: - user = User.new(name: "", email: "invalid") if user.save puts "✅ User saved successfully!" else puts "❌ Validation failed:" user.errors.full_messages.each do |error| puts " - #{error}" end end
- Use save! for development debugging: - begin user.save! # Will raise with detailed error rescue CQL::RecordInvalid => ex puts "Validation errors:" ex.record.errors.full_messages.each { |msg| puts " - #{msg}" } end
❌ Issue: Transaction Rollback Problems
# Transaction doesn't rollback as expectedSolution:
- Ensure exceptions are raised: - UserDB.transaction do user1.save! # Use ! methods to raise on failure user2.save! # Explicitly raise for business logic errors raise "Business rule violation" if some_condition end
- Handle rollback explicitly: - UserDB.transaction do |tx| begin user1.save! user2.save! # Some complex logic that might fail raise "Error" if validation_fails rescue ex puts "Rolling back transaction: #{ex.message}" tx.rollback raise ex # Re-raise to exit transaction block end end
⚡ Performance Issues
❌ Issue: Slow Queries
Debugging Steps:
- Enable query logging: - # In your schema definition schema = CQL::Schema.define(:myapp, adapter: adapter, uri: uri) do # Enable logging in development log_level = :debug if ENV["ENV"]? == "development" end
- Analyze query performance: - # Time your queries start_time = Time.monotonic users = User.where(active: true).limit(100).all duration = Time.monotonic - start_time puts "Query took: #{duration.total_milliseconds}ms"
- Check for N+1 queries: - # ❌ N+1 problem users = User.all users.each do |user| puts user.posts.count # Triggers one query per user end # ✅ Use eager loading (when available) users = User.join(:posts).all users.each do |user| puts user.posts.count # Posts already loaded end
❌ Issue: High Memory Usage
Solutions:
- Use pagination for large datasets: - # ❌ Loading all records users = User.all # Could load millions of records # ✅ Use pagination page_size = 100 offset = 0 loop do batch = User.limit(page_size).offset(offset).all break if batch.empty? batch.each { |user| process_user(user) } offset += page_size end
- Use select to limit columns: - # ❌ Loading all columns users = User.all # ✅ Load only needed columns users = User.select(:id, :name, :email).all
🛠️ Development Tips
🔍 Debugging Techniques
- Enable SQL logging: - # See generated SQL queries users = User.where(active: true) puts users.to_sql # Shows: ["SELECT * FROM users WHERE active = ?", [true]]
- Inspect model state: - user = User.new(name: "Test") puts "New record? #{user.new_record?}" puts "Persisted? #{user.persisted?}" puts "Valid? #{user.valid?}" puts "Errors: #{user.errors.full_messages}"
- Check database state: - # Verify database connection puts "Tables: #{MySchema.tables.keys}" # Check record counts puts "Users: #{User.count}" puts "Posts: #{Post.count}"
⚡ Quick Fixes
- Reset database in development: - # ⚠️ Development only! rm db/development.sqlite3 # For SQLite crystal run db/migrate.cr crystal run db/seed.cr # If you have a seed file
- Clear and rebuild schema cache: - # Force schema reload MySchema.build
- Check for pending migrations: - # In your application pending = MySchema.pending_migrations if pending.any? puts "⚠️ Pending migrations: #{pending.map(&.version)}" end
🆘 Getting More Help
📚 Additional Resources
- CQL Documentation - Complete documentation 
- GitHub Issues - Report bugs or get help 
- Crystal Forum - Community discussions 
- Crystal Discord - Real-time chat support 
🐛 Reporting Issues
When reporting issues, please include:
- Crystal version: - crystal --version
- CQL version: Check your - shard.yml
- Database type and version 
- Minimal reproduction code 
- Full error message and stack trace 
- Expected vs actual behavior 
💡 Best Practices
- Use transactions for multi-step operations 
- Validate input before database operations 
- Handle exceptions gracefully in production 
- Use environment variables for sensitive configuration 
- Test database operations with proper fixtures 
- Monitor query performance in production 
- Keep migrations reversible when possible 
💡 Pro Tip: Most CQL issues are related to schema mismatches or missing validations. Always verify your schema definitions match your database structure and use proper error handling patterns.
Still stuck? Check the FAQ section or reach out to the community for help! 🤝
Last updated
Was this helpful?
