Common Issues (50+)
Common Issues & Solutions
Section titled “Common Issues & Solutions”Troubleshooting guide for the 50 most common FraiseQL issues.
Connection Issues (10)
Section titled “Connection Issues (10)”Connection Refused
Section titled “Connection Refused”Problem: Error: connect ECONNREFUSED 127.0.0.1:5432
Causes:
- Database not running
- Wrong host/port
- Firewall blocking
- Wrong credentials
Solutions:
# 1. Check database is runningdocker-compose pspsql -h localhost -U user -c "SELECT 1"
# 2. Verify DATABASE_URLecho $DATABASE_URL# Should be: postgresql://user:pass@host:5432/db
# 3. Test connectionpsql postgresql://user:pass@host:5432/db -c "SELECT 1"
# 4. Check firewall# PostgreSQL default port: 5432# MySQL default port: 3306ufw allow 5432Too Many Connections
Section titled “Too Many Connections”Problem: FATAL: too many connections for role "user"
Cause: All database connections exhausted
Solutions:
- Increase connection limit:
PGBOUNCER_MAX_POOL_SIZE=30 # Increase from 20- Check who’s using connections:
SELECT usename, count(*) FROM pg_stat_activity GROUP BY usename;
-- Kill idle connectionsSELECT pg_terminate_backend(pid)FROM pg_stat_activityWHERE state = 'idle' AND query_start < now() - interval '10 minutes';SHOW PROCESSLIST;
-- Kill idle connections (older than 10 minutes)SELECT CONCAT('KILL ', id, ';')FROM INFORMATION_SCHEMA.PROCESSLISTWHERE COMMAND = 'Sleep' AND TIME > 600;# SQLite doesn't use connection pooling like other databases# It uses a single connection with WAL mode for concurrency# Check for lock issues instead:# Monitor .db-wal and .db-shm filesls -lh *.db*SELECT spid, loginame, status, cmdFROM master.dbo.sysprocessesWHERE spid > 50; -- System processes use 1-50
-- Kill idle connectionsKILL <spid> -- Where spid is the connection ID to terminate- Restart FraiseQL:
docker-compose restart fraiseqlConnection Timeout
Section titled “Connection Timeout”Problem: Error: connect ETIMEDOUT
Causes:
- Database overloaded
- Network latency
- Connection timeout too low
Solutions:
- Check database load:
SELECT * FROM pg_stat_activity WHERE state != 'idle';
-- Get summary of connectionsSELECT count(*) as total_connections, sum(case when state = 'active' then 1 else 0 end) as active, sum(case when state = 'idle' then 1 else 0 end) as idleFROM pg_stat_activity;SHOW PROCESSLIST;
-- Get summary of connectionsSELECT COUNT(*) as total_connections, COUNT(CASE WHEN COMMAND != 'Sleep' THEN 1 END) as active, COUNT(CASE WHEN COMMAND = 'Sleep' THEN 1 END) as idleFROM INFORMATION_SCHEMA.PROCESSLIST;# SQLite single-connection model, check for lock waits# Enable query logging to see if queries are blockingsqlite3 database.db ".log stdout"SELECT spid, loginame, status, cmd, cpu, physical_ioFROM master.dbo.sysprocessesWHERE spid > 50 AND status != 'sleeping';
-- Get connection summarySELECT COUNT(*) as total_connections, SUM(CASE WHEN status = 'running' THEN 1 ELSE 0 END) as activeFROM master.dbo.sysprocessesWHERE spid > 50;- Increase timeout:
PGBOUNCER_CONNECTION_TIMEOUT=60 # Increase from 30- Check network latency:
ping database.example.comtraceroute database.example.com- Check database resource usage:
df -hfree -hConnection Lost During Query
Section titled “Connection Lost During Query”Problem: Error: Connection lost after X seconds
Causes:
- Query running too long
- Database restarting
- Network interruption
Solutions:
- Check for long-running queries:
SELECT pid, usename, state, now() - query_start as duration, queryFROM pg_stat_activityWHERE state != 'idle'ORDER BY duration DESC;
-- Kill long-running queries (older than 30 minutes)SELECT pg_terminate_backend(pid)FROM pg_stat_activityWHERE state != 'idle' AND now() - query_start > interval '30 minutes';SELECT ID, USER, TIME, STATE, INFOFROM INFORMATION_SCHEMA.PROCESSLISTWHERE COMMAND != 'Sleep'ORDER BY TIME DESC;
-- Kill long-running queries (older than 1800 seconds)SELECT CONCAT('KILL ', id, ';')FROM INFORMATION_SCHEMA.PROCESSLISTWHERE TIME > 1800 AND COMMAND != 'Sleep';# SQLite doesn't have long-running query tracking like other databases# Monitor query execution with EXPLAIN QUERY PLANsqlite3 database.db "EXPLAIN QUERY PLAN SELECT ..."
# Check for locks# Monitor .db-wal file size for growing write-ahead logsls -lh database.db-walSELECT spid, loginame, status, cmd, cpu, datediff(second, login_time, getdate()) as session_duration_sec, datediff(second, last_batch, getdate()) as idle_secondsFROM master.dbo.sysprocessesWHERE spid > 50 AND status = 'running'ORDER BY cpu DESC;
-- Kill long-running queryKILL <spid>- Increase statement timeout:
STATEMENT_TIMEOUT=300000 # 5 minutes- Optimize slow query:
-- Add indexes, reduce complexityCREATE INDEX idx_posts_user ON posts(user_id);- Enable connection retry:
DATABASE_URL=postgresql://...?application_name=fraiseql&statement_timeout=300000SSL Certificate Verification Failed
Section titled “SSL Certificate Verification Failed”Problem: Error: certificate verify failed
Cause: SSL certificate issue with database
Solutions:
# 1. Disable SSL verification (development only)DATABASE_URL=postgresql://user:pass@host/db?sslmode=disable
# 2. Use correct certificateDATABASE_URL=postgresql://user:pass@host/db?sslmode=require&sslcert=/path/to/cert.pem
# 3. Check certificate validityopenssl x509 -in cert.pem -noout -datesopenssl x509 -in cert.pem -noout -issuer
# 4. Update CA bundle# AWS RDSwget https://truststore.amazonaws.com/rds-ca-2019-root.pemDatabase Server Closed Connection
Section titled “Database Server Closed Connection”Problem: Error: server closed the connection unexpectedly
Causes:
- Database restarting
- Query killed by administrator
- Connection idle timeout
Solutions:
# 1. Check database logstail -f /var/log/postgresql/postgresql.log
# 2. Increase idle timeout# PostgreSQL: modify idle_in_transaction_session_timeoutALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';SELECT pg_reload_conf();
# 3. Add automatic reconnection# FraiseQL handles this automatically# But verify in logs: LOG_LEVEL=debug
# 4. Check for database crashes# Check /var/log/messages for OOM killsdmesg | tail -50Authentication Failed
Section titled “Authentication Failed”Problem: FATAL: password authentication failed for user "user"
Cause: Wrong password or user doesn’t exist
Solutions:
# 1. Verify credentialsecho $DATABASE_URL
# 2. Reset password (PostgreSQL)psql -U postgresALTER USER user WITH PASSWORD 'newpassword';
# 3. Test with correct credentialspsql postgresql://newuser:newpassword@host/db
# 4. Create user if doesn't existCREATE USER fraiseql WITH PASSWORD 'secure-password';GRANT ALL PRIVILEGES ON DATABASE fraiseql TO fraiseql;Connection Pool Exhaustion
Section titled “Connection Pool Exhaustion”Problem: Requests timing out, unable to get database connection
Solutions:
- Check connection pool usage:
# Prometheus metricfraiseql_db_connections_used / fraiseql_db_connections_max- Monitor connections by database:
# Monitor connections over timewatch -n 1 'psql -c "SELECT count(*) as total, sum(case when state = \"active\" then 1 else 0 end) as active FROM pg_stat_activity"'
# Kill idle connections periodicallypsql -c "SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE state = 'idle' AND query_start < now() - interval '5 minutes';"# Monitor connectionswatch -n 1 'mysql -e "SHOW PROCESSLIST; SELECT COUNT(*) as total FROM INFORMATION_SCHEMA.PROCESSLIST;"'
# Kill idle connections periodicallymysql -e "SELECT CONCAT('KILL ', id, ';') FROM INFORMATION_SCHEMA.PROCESSLIST WHERE COMMAND = 'Sleep' AND TIME > 300" | mysql# SQLite uses single connection in WAL mode# Monitor WAL file for lockswatch -n 1 'ls -lh *.db-wal'
# Check for unfinished transactionssqlite3 database.db "PRAGMA integrity_check;"# Monitor connectionswatch -n 1 'sqlcmd -e "SELECT COUNT(*) as total, SUM(CASE WHEN status = \"running\" THEN 1 ELSE 0 END) as active FROM master.dbo.sysprocesses WHERE spid > 50"'
# Kill idle connections using SQLsqlcmd -e "DECLARE @maxIdleSeconds INT = 300; SELECT spid FROM master.dbo.sysprocesses WHERE spid > 50 AND datediff(second, last_batch, getdate()) > @maxIdleSeconds"- Increase pool size:
PGBOUNCER_MAX_POOL_SIZE=50- Implement connection reset:
docker-compose restart fraiseqlWrong Database URL Format
Section titled “Wrong Database URL Format”Problem: Error: invalid connection URI: ...
Cause: DATABASE_URL format incorrect
Solutions:
# PostgreSQL formatpostgresql://user:password@host:5432/database?sslmode=require
# MySQL formatmysql://user:password@host:3306/database
# SQLite formatsqlite:///./data/fraiseql.db
# SQL Server formatmssql://user:password@host:1433/database?encrypt=true
# Verify URL encoding# Special characters in password need URL encodingpassword: P@ss%wordURL encoded: P%40ss%25wordNetwork Unreachable
Section titled “Network Unreachable”Problem: Error: Network is unreachable
Cause: Database host unreachable
Solutions:
# 1. Check DNS resolutionnslookup database.example.comdig database.example.com
# 2. Check routingtraceroute database.example.com
# 3. Check firewall rulesiptables -L -nufw status
# 4. Check security group (AWS)aws ec2 describe-security-groups --group-ids sg-xxxxx
# 5. Verify network connectivityping database.example.comtelnet database.example.com 5432nc -zv database.example.com 5432Authentication & Authorization (8)
Section titled “Authentication & Authorization (8)”Invalid Token
Section titled “Invalid Token”Problem: Error: Invalid token
Causes:
- Token expired
- Token signed with different secret
- Token format incorrect
Solutions:
# 1. Check token expirationpython -c "import jwttoken = 'your-token'jwt.decode(token, options={'verify_signature': False})"
# 2. Verify JWT_SECRET matches# Check .env fileecho $JWT_SECRET
# 3. Check token format# Should be: Authorization: Bearer <token># Not: Authorization: <token>
# 4. Generate new tokenimport jwttoken = jwt.encode( {'user_id': 123, 'exp': datetime.datetime.utcnow() + datetime.timedelta(hours=1)}, 'secret', algorithm='HS256')Missing Authorization Header
Section titled “Missing Authorization Header”Problem: Error: Missing Authorization header
Cause: Request doesn’t include authentication
Solutions:
# 1. Add Authorization headercurl -H "Authorization: Bearer <token>" http://localhost:8000/graphql
# 2. Verify client sends header# JavaScriptfetch(url, { headers: { 'Authorization': `Bearer ${token}` }})
# 3. Check middleware is enabled# FraiseQL should extract token automatically# Verify in logs: LOG_LEVEL=debug
# 4. For unauthenticated endpoints# Mark query with @public@fraiseql.querydef public_posts() -> list[Post]: passToken Expired
Section titled “Token Expired”Problem: Error: Token has expired
Solutions:
# 1. Check token expiration time# Tokens typically expire in 1 hour
# 2. Implement token refresh# Client gets new token when old one expiresPOST /auth/refreshBody: { "refresh_token": "..." }Response: { "access_token": "...", "expires_in": 3600 }
# 3. Increase token expiration (not recommended for security)JWT_EXPIRY=86400 # 24 hours
# 4. Implement sliding window# Token automatically refreshes if used within last 5 minutesInsufficient Permissions
Section titled “Insufficient Permissions”Problem: Error: User does not have permission to access this field
Cause: User role lacks required permission
Solutions:
# 1. Check user roleSELECT user_id, role FROM user_roles WHERE user_id = 123;
# 2. Check role permissionsSELECT rp.permission_id, p.nameFROM role_permissions rpJOIN permissions p ON rp.permission_id = p.idWHERE rp.role_id = 1;
# 3. Grant permission to roleINSERT INTO role_permissions (role_id, permission_id)VALUES (1, (SELECT id FROM permissions WHERE name = 'read:posts'));
# 4. Check field-level authorization@fraiseql.field('User', 'email')def email(user, info): # Only show email if user is admin or viewing own profile if info.context.user.id == user.id or info.context.user.role == 'admin': return user.email raise PermissionError('Cannot view email')Wrong Scope
Section titled “Wrong Scope”Problem: Error: Scope "write:posts" not found
Cause: Scope doesn’t exist or not granted to user
Solutions:
# 1. Check available scopesSELECT * FROM permissions;
# 2. Grant scope to userINSERT INTO user_roles (user_id, role_id)VALUES (123, (SELECT id FROM roles WHERE name = 'editor'));
# 3. Check scope is spelled correctly# Scopes are case-sensitivewrite:posts != WRITE:POSTS
# 4. Define custom scope@fraiseql.mutation(requires_scope="write:posts")def create_post(title: str) -> Post: passAccess Denied
Section titled “Access Denied”Problem: Error: Access denied for user 'user'@'host'
Cause: User doesn’t have permission on resource
Solutions:
# 1. Check row-level security (RLS)SELECT * FROM pg_policies;
# 2. Set user context for RLSSET app.user_id = 123;
# 3. Implement RLS policyCREATE POLICY posts_owner ON postsUSING (user_id = current_setting('app.user_id')::integer);
# 4. Check tenant isolation# Verify tenant_id matches current_tenantToken Revoked
Section titled “Token Revoked”Problem: Error: Token has been revoked
Cause: Token was explicitly invalidated
Solutions:
# 1. Implement token blacklistCREATE TABLE revoked_tokens ( token_id UUID PRIMARY KEY, revoked_at TIMESTAMP DEFAULT NOW());
# 2. On logout, add token to blacklistINSERT INTO revoked_tokens (token_id) VALUES (uuid);
# 3. On each request, check if revokedSELECT COUNT(*) FROM revoked_tokens WHERE token_id = $1;
# 4. For immediate revocation (e.g., stolen token)DELETE FROM revoked_tokens WHERE revoked_at < NOW() - INTERVAL '7 days';CORS Preflight Failed
Section titled “CORS Preflight Failed”Problem: Error: CORS policy blocked request
Cause: CORS configuration incorrect
Solutions:
# 1. Check CORS_ORIGINS environment variableecho $CORS_ORIGINS
# 2. Add frontend originCORS_ORIGINS=https://app.example.com,https://localhost:3000
# 3. Check preflight request (OPTIONS)curl -X OPTIONS http://localhost:8000/graphql \ -H "Origin: https://app.example.com"
# 4. Verify response headers# Should include:# Access-Control-Allow-Origin: https://app.example.com# Access-Control-Allow-Methods: POST, GET, OPTIONS# Access-Control-Allow-Headers: Content-Type, AuthorizationQuery Issues (10)
Section titled “Query Issues (10)”Query Returns Empty
Section titled “Query Returns Empty”Problem: Query executes but returns no data
Causes:
- Filtering too restrictive
- No matching records
- Row-level security filtering
- Soft-deleted records
Solutions:
# 1. Check data exists in databaseSELECT COUNT(*) FROM users;
# 2. Check filtering logic# This returns nothing:users(name_eq: "NonExistent") { id name }
# 3. Check RLS isn't filtering all resultsSELECT * FROM users WHERE RLS_condition;
# 4. Check soft deletes# Might be filtering out deleted recordsSELECT COUNT(*) FROM users WHERE deleted_at IS NULL;
# 5. Test with simpler queryquery { users { id } }Type Mismatch Error
Section titled “Type Mismatch Error”Problem: Error: Field "id" expects type ID but got String
Cause: Value type doesn’t match schema
Solutions:
# 1. Check field type in schema@fraiseql.typeclass User: id: ID # Correct # NOT: id: str
# 2. Convert value to correct type# JavaScriptconst userId = parseInt(stringId) // Convert String to Intconst id = stringId // Already a String
# 3. Check GraphQL query# String IDs need quotesquery { user(id: "123") { ... } }# Not: query { user(id: 123) { ... } }
# 4. Update schema if neededclass User: id: int # If you need integer IDs email: strNull Relationships
Section titled “Null Relationships”Problem: user.posts is null but should have data
Causes:
- Foreign key doesn’t match
- Related records don’t exist
- Related records are deleted
- Join condition wrong
Solutions:
# 1. Check foreign key valuesSELECT user_id, COUNT(*) FROM posts GROUP BY user_id;
# 2. Verify relationship existsSELECT p.id, p.user_id, u.idFROM posts pLEFT JOIN users u ON p.user_id = u.idWHERE p.id = 123;
# 3. Check schema relationship definition@fraiseql.typeclass Post: user_id: ID user: User # Should auto-join on user_id
# 4. Check for soft deletesSELECT * FROM users WHERE id = 123 AND deleted_at IS NULL;
# 5. Verify database foreign keySELECT constraint_name, table_name, column_nameFROM information_schema.key_column_usageWHERE table_name = 'posts';Silent Failures
Section titled “Silent Failures”Problem: Mutation runs but data doesn’t change
Causes:
- Transaction rolled back
- Trigger preventing change
- Permission denied
- Validation failed
Solutions:
# 1. Check mutation response for errorsmutation { createPost(title: "...", content: "...") { ... # Will show errors if any }}
# 2. Check database triggersSELECT * FROM information_schema.triggers WHERE table_name = 'posts';
# 3. Enable transaction loggingBEGIN;UPDATE posts SET title = 'New' WHERE id = 123;-- Check if update succeededSELECT title FROM posts WHERE id = 123;ROLLBACK; -- Or COMMIT
# 4. Check for validation errors# Review input data for NULL, empty strings, etc.
# 5. Check permissionsSELECT grantee, privilege_typeFROM information_schema.role_table_grantsWHERE table_name = 'posts';Field Not Found Error
Section titled “Field Not Found Error”Problem: Error: Cannot query field "unknownField" on type "User"
Cause: Field doesn’t exist in schema
Solutions:
# 1. Check schema definition@fraiseql.typeclass User: id: ID name: str # No "unknown_field" defined
# 2. Use correct field namequery { user { id name } } # Correct# Not: query { user { unknownField } }
# 3. Check for typos# These are different:created_atcreatedAtcreateddate
# 4. Run introspection to see available fieldsquery { __type(name: "User") { fields { name type { name kind } } }}
# 5. Check field visibility# Might require certain permissionsPagination Not Working
Section titled “Pagination Not Working”Problem: limit and offset not working as expected
Solutions:
# 1. Check pagination parameters are correctquery { users(limit: 10, offset: 0) { id } # Correct # Not: users(page: 1, pageSize: 10)}
# 2. Verify total countquery { users(limit: 10, offset: 0) { id } usersCount # Total count without pagination}
# 3. Use cursor-based pagination for better performancequery { users(first: 10, after: "cursor-from-previous") { edges { node { id } cursor } pageInfo { hasNextPage } }}
# 4. Check ordering is stable# Without ORDER BY, pagination order might change@fraiseql.querydef users(limit: int = 10, offset: int = 0) -> list[User]: # Must order consistently # ORDER BY id, created_at DESC passAggregation Returns Wrong Value
Section titled “Aggregation Returns Wrong Value”Problem: COUNT(*) or SUM() returns unexpected value
Causes:
- Null values in aggregation
- Duplicate records
- Filter not applied
- Group by missing
Solutions:
# 1. Check for NULL valuesSELECT COUNT(*) FROM posts; -- Counts rowsSELECT COUNT(id) FROM posts; -- Counts non-null idsSELECT COUNT(DISTINCT user_id) FROM posts; -- Unique users
# 2. Check for duplicatesSELECT id, COUNT(*) FROM posts GROUP BY id HAVING COUNT(*) > 1;
# 3. Verify filtering appliedSELECT COUNT(*) FROM posts WHERE published = true;
# 4. Check GROUP BY logicSELECT user_id, COUNT(*) as post_countFROM postsGROUP BY user_id;
# 5. Handle NULL in aggregationSELECT SUM(COALESCE(likes, 0)) FROM posts;Ordering Not Applied
Section titled “Ordering Not Applied”Problem: Results not in expected order
Solutions:
# 1. Check ordering parameterquery { users(orderBy: "name ASC") { id name }}
# 2. Verify field exists# Can't order by non-existent field
# 3. Check data types# Can't order mixed types (string + number)
# 4. Check NULL handling# NULLs usually sort to endSELECT * FROM users ORDER BY name ASC NULLS LAST;
# 5. Add secondary sort for stabilityquery { users(orderBy: "created_at DESC, id DESC") { id created_at }}Performance Issues (8)
Section titled “Performance Issues (8)”Slow Queries
Section titled “Slow Queries”Problem: p95 latency > 500ms
Solutions:
# 1. Identify slow queries (PostgreSQL)SELECT mean_exec_time, query FROM pg_stat_statementsORDER BY mean_exec_time DESC LIMIT 10;
# 2. Analyze slow queryEXPLAIN ANALYZE SELECT ...;
# 3. Add missing indexesCREATE INDEX idx_posts_user_id ON posts(user_id);CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
# 4. Optimize query# Use LIMIT instead of full table scan# Add WHERE instead of filtering in app# Use aggregation at database level
# 5. Check N+1 problems# Should have < 5 queries for any requestLOG_LEVEL=debug fraiseql runN+1 Queries
Section titled “N+1 Queries”Problem: 100 queries for 10-item result
Cause: Resolving relationships without batching
Solutions:
# 1. Verify FraiseQL automatic batching is working# You should see batched queries like:# SELECT * FROM users LIMIT 10# SELECT * FROM posts WHERE user_id IN (1, 2, ..., 10)
# 2. Check logs for individual queriesLOG_LEVEL=debug
# 3. Monitor query count# Should be ≤ 3 for benchmark query
# 4. If still N+1, check for:# - Circular relationships# - Computed fields that query separately# - Middleware making additional queries
# 5. Simplify query while testingquery { users(limit: 5) { id name } # Add relationships one at a time to find culprit}Memory Leak
Section titled “Memory Leak”Problem: Memory usage grows over time
Solutions:
# 1. Monitor memorywatch -n 1 'free -h'docker stats fraiseql
# 2. Check for connection leaks# Connections accumulate if not closed properly
# 3. Restart periodicallydocker-compose restart fraiseql
# 4. Increase memory limitsdocker-compose up -d --memory=2g fraiseql
# 5. Profile applicationpip install memory-profilerpython -m memory_profiler app.py
# 6. Check for circular references# Ensure objects can be garbage collectedHigh CPU Usage
Section titled “High CPU Usage”Problem: CPU > 80%
Causes:
- Complex queries
- Too many concurrent requests
- Inefficient algorithm
Solutions:
# 1. Check which query uses CPULOG_LEVEL=debug
# 2. Profile CPU usagepython -m cProfile -s cumtime app.py
# 3. Optimize complex query# Simplify WHERE conditions# Add indexes# Use LIMIT
# 4. Increase concurrency# Python: Add workers# Docker: Add instances
# 5. Cache expensive computations@cached(ttl=3600)def expensive_query(): passDatabase Connection Pool Exhaustion
Section titled “Database Connection Pool Exhaustion”Problem: “Cannot get a database connection” errors
Solutions (See Connection Issues section)
Cache Hit Rate Low
Section titled “Cache Hit Rate Low”Problem: Cache hit rate < 50%
Causes:
- TTL too short
- Too many unique queries
- Cache not enabled
Solutions:
# 1. Increase TTL@cached(ttl=86400) # 24 hours instead of 1 hour
# 2. Check cache is enabled# Redis connection working?redis-cli ping
# 3. Monitor cache stats# Prometheus: cache_hits / (cache_hits + cache_misses)
# 4. Adjust caching strategy# Cache at query level, not field level# Cache stable data, not volatile data
# 5. Implement cache warming# Preload common queries on startupDatabase Disk Full
Section titled “Database Disk Full”Problem: “No space left on device” errors
Solutions:
# 1. Check disk spacedf -h
# 2. Find large tablesSELECT schemaname, tablename, pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename))FROM pg_tablesORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESCLIMIT 10;
# 3. Remove old dataDELETE FROM audit_logs WHERE created_at < NOW() - INTERVAL '90 days';
# 4. Vacuum database (cleanup)VACUUM ANALYZE;
# 5. Expand storage# Docker: Mount larger volume# Cloud: Resize RDS storagedocker-compose down# Edit docker-compose.yml volumesdocker-compose up -dSchema & Validation Issues (8)
Section titled “Schema & Validation Issues (8)”Invalid Schema Definition
Section titled “Invalid Schema Definition”Problem: Error: Invalid schema
Causes:
- Circular imports
- Invalid type reference
- Missing type annotation
Solutions:
# 1. Check for circular imports# A → B → A
# 2. Use forward references@fraiseql.typeclass Post: user: 'User' # String reference to avoid circular import
@fraiseql.typeclass User: posts: list['Post']
# 3. Check type annotationsclass User: id: ID # Correct name: str # NOT: name (missing type) # NOT: name: (incomplete)
# 4. Import types correctlyfrom fraiseql import ID, FraiseQL
# 5. Validate schemafraiseql validateRequired Field Null
Section titled “Required Field Null”Problem: Error: Field "name" of required type String! cannot be null
Cause: NULL value provided for non-null field
Solutions:
# 1. Provide value for required fieldmutation { createUser(name: "Alice", email: "alice@example.com") { id } # Not: createUser(name: null, email: "...")}
# 2. Check schema definition# Required: String! (with !)# Optional: String (without !)
# 3. Check default values@fraiseql.mutationdef create_user( name: str, # Required email: str = "default@example.com" # Optional with default) -> User: pass
# 4. Check database constraints# Column might be NOT NULLInvalid Input Type
Section titled “Invalid Input Type”Problem: Error: Expected type Int but got String
Solutions (See Query Issues: Type Mismatch)
Duplicate Type Definition
Section titled “Duplicate Type Definition”Problem: Error: Type "User" defined multiple times
Cause: Same type defined in multiple files
Solutions:
# 1. Check for duplicate @fraiseql.type# Only define each type once
# 2. Use imports instead of redefinition# In module_a.py@fraiseql.typeclass User: pass
# In module_b.pyfrom module_a import User # Import, don't redefine
# 3. Check file organization# Each type should be in one place# src/schema/models.pyField Name Conflict
Section titled “Field Name Conflict”Problem: Error: Field name "id" conflicts with...
Cause: Field defined multiple times with different types
Solutions:
# 1. Check field definitions are consistent@fraiseql.typeclass User: id: ID # Integer ID id: str # Conflict! Can't redefine
# 2. Choose one type for each field@fraiseql.typeclass User: id: ID # Correct name: str
# 3. Check inheritanceclass BaseUser: id: ID
class User(BaseUser): id: str # Conflict with parent!Enum Value Not Found
Section titled “Enum Value Not Found”Problem: Error: "invalid_status" is not a valid Status
Cause: Enum value doesn’t exist
Solutions:
# 1. Define enum valuesfrom enum import Enum
class PostStatus(str, Enum): DRAFT = "draft" PUBLISHED = "published" ARCHIVED = "archived"
# 2. Use correct valuemutation { updatePost(status: "published") { id } # Not: updatePost(status: "invalid_status")}
# 3. Check enum spelling (case-sensitive)DRAFT != draftCustom Scalar Not Registered
Section titled “Custom Scalar Not Registered”Problem: Error: Unknown scalar type "JSON"
Cause: Custom scalar not defined
Solutions:
# 1. Define custom scalar@fraiseql.scalarclass JSON: @staticmethod def serialize(value): return json.dumps(value)
@staticmethod def parse_value(value): return json.loads(value)
# 2. Use in schema@fraiseql.typeclass Post: metadata: JSON # Now valid
# 3. Check scalar is registered globallyfraiseql.register_scalar(JSON)Deployment Issues (6)
Section titled “Deployment Issues (6)”Container Won’t Start
Section titled “Container Won’t Start”Problem: Docker container exits immediately
Solutions:
# 1. Check logsdocker logs fraiseqldocker logs --tail 100 fraiseql
# 2. Run in foreground to see errorsdocker run -it fraiseql fraiseql run
# 3. Check environment variablesdocker exec fraiseql env# Verify DATABASE_URL, JWT_SECRET set
# 4. Verify image built correctlydocker build -t fraiseql:test .docker run fraiseql:test python -c "import fraiseql; print(fraiseql.__version__)"
# 5. Check health checkHEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD curl -f http://localhost:8000/health/live || exit 1Port Already In Use
Section titled “Port Already In Use”Problem: Error: Port 8000 already in use
Solutions:
# 1. Find process using portlsof -i :8000netstat -tlnp | grep 8000
# 2. Kill processkill -9 <PID>
─
# 4. Or stop existing servicedocker-compose downOut of Memory
Section titled “Out of Memory”Problem: Error: OOM Killer
Solutions:
# 1. Increase memory limit# Docker Composefraiseql: deploy: resources: limits: memory: 2G
# 2. Check memory usagedocker stats fraiseqlfree -h
# 3. Reduce batch sizeBATCH_SIZE=100 # Smaller batches use less memory
# 4. Restart servicedocker-compose restart fraiseqlNetworking Not Working
Section titled “Networking Not Working”Problem: Container can’t communicate with database
Solutions:
# 1. Check networkdocker network lsdocker network inspect <network>
# 2. Verify service name# In docker-compose.yml, database service name should match DATABASE_URL
# 3. Test connectivitydocker exec fraiseql ping postgresdocker exec fraiseql psql -h postgres -U user -c "SELECT 1"
# 4. Check firewalldocker exec fraiseql nc -zv postgres 5432
# 5. Restart networkdocker network prunedocker-compose downdocker-compose up -dVolume Mount Issues
Section titled “Volume Mount Issues”Problem: Files not visible in container
Solutions:
# 1. Check volume is mounteddocker inspect fraiseql | grep -A 5 Mounts
# 2. Verify mount pathdocker-compose.yml: volumes: - .:/app # Host path:Container path
# 3. Check permissions# File permissions might prevent accesschmod 755 /path/to/app
# 4. Restart containerdocker-compose restart fraiseql
# 5. For production, don't use volumes# Copy files in Dockerfile insteadCOPY . /appSummary Table
Section titled “Summary Table”| Category | Issue | Time to Fix |
|---|---|---|
| Connection | Connection refused | 2 min |
| Connection | Too many connections | 5 min |
| Auth | Invalid token | 3 min |
| Auth | Insufficient permissions | 5 min |
| Query | Empty results | 5 min |
| Query | Type mismatch | 3 min |
| Performance | Slow queries | 15 min |
| Performance | N+1 queries | 10 min |
| Schema | Invalid schema | 10 min |
| Deployment | Container won’t start | 5 min |
Next Steps
Section titled “Next Steps”- Find your issue in this list
- Follow the solutions
- If not working, check Database-Specific Issues
- Still stuck? Ask on Discord