Skip to content
Troubleshooting

Troubleshooting

Diagnose and fix common Melange issues.

Using melange doctor

melange doctor --db "$DATABASE_URL"

Doctor runs six categories of checks against your database:

  1. Schema File: exists, parses correctly, no cyclic dependencies.
  2. Migration State: melange_migrations table exists, schema is in sync, codegen version matches.
  3. Generated Functions: dispatcher and per-relation functions are present, no orphans from previous schemas.
  4. Tuples Source: melange_tuples view exists with the correct columns.
  5. Data Health: tuple count, types and relations validate against the schema.
  6. Performance: UNION ALL usage, missing expression indexes on ::text cast columns.

Use --verbose for detailed output (exact checksums, function lists, specific invalid tuples):

melange doctor --verbose

Skip performance checks if you only need structural validation:

melange doctor --skip-performance

Common Errors

“relation melange_tuples does not exist”

The melange_tuples view has not been created, or it was created in a different schema than the one your connection uses.

Fix: create the view. See Creating Your Tuples View.

“function check_permission does not exist”

The migration has not been run, or it was run against a different database or schema.

Fix: run melange migrate --db "$DATABASE_URL".

Permission checks always return false

The tuples view exists but returns no rows for the subject/object/relation being checked.

Debug:

-- Check what tuples exist for the subject
SELECT * FROM melange_tuples WHERE subject_type = 'user' AND subject_id = 'alice';

-- Check what tuples exist for the object
SELECT * FROM melange_tuples WHERE object_type = 'repository' AND object_id = '42';

Common causes:

  • Relation names in the view don’t match the schema (e.g., 'is_member' vs 'member').
  • ID types aren’t cast to text (user_id vs user_id::text).
  • The domain table has no data for the given subject/object.

Permission checks always return true

A wildcard subject (user:*) is granting broader access than intended.

Debug:

SELECT * FROM melange_tuples WHERE subject_id = '*';

Check that wildcard rows are scoped to the correct relation and object type.

Slow permission checks

Debug:

EXPLAIN ANALYZE SELECT check_permission('user', '123', 'can_read', 'repository', '456');

Look for Seq Scan in the output. Common causes:

  • Missing expression indexes on ::text cast columns. Run melange doctor for specific CREATE INDEX recommendations.
  • Large source tables without appropriate composite indexes.
  • Complex schema patterns (deeply nested exclusions or parent chains).

See Scaling for optimization strategies.

Schema validation errors

melange validate

Common causes:

  • Syntax errors in the .fga file. The error message includes the line number.
  • Cyclic dependencies in implied-by relationships (e.g., define a: b and define b: a).
  • References to undefined types or relations.

Migration “schema unchanged” when it shouldn’t be

Melange tracks schema changes via SHA256 checksum. If you’ve updated Melange itself but not the schema, the new codegen may produce different SQL.

Fix: force re-migration:

melange migrate --force

Schema out of sync after updating Melange

melange doctor detects when the codegen version has changed since the last migration.

Fix: run melange migrate --force to regenerate all SQL functions with the current Melange version.

Debugging Techniques

Preview Generated SQL

melange migrate --dry-run

Outputs the complete SQL that would be executed. Redirect to a file for inspection:

melange migrate --dry-run > migration.sql

Inspect Tuple Data

-- All tuples for a specific object
SELECT * FROM melange_tuples
WHERE object_type = 'repository' AND object_id = '42'
ORDER BY relation, subject_type, subject_id;

-- Count tuples by type
SELECT object_type, relation, count(*)
FROM melange_tuples
GROUP BY object_type, relation
ORDER BY count DESC;

Query Plan Analysis

EXPLAIN ANALYZE
SELECT * FROM melange_tuples
WHERE object_type = 'repository' AND object_id = '42'
  AND relation = 'can_read' AND subject_type = 'user';

Look for:

  • Seq Scan with Filter: lines containing ::text casts. This means expression indexes are needed.
  • High actual time values on individual branches of the UNION ALL.

Check Effective Configuration

melange config show --source

Shows which config file is in use and the effective values after merging defaults, config file, and environment variables.

Getting Help

If you’re stuck, open an issue at github.com/pthm/melange/issues with:

  • Your .fga schema
  • The melange doctor --verbose output
  • The error message or unexpected behavior
  • Your Melange version (melange version)

Next Steps

  • CLI Reference: full command documentation and exit codes
  • Errors: error types and sentinel values
  • Scaling: performance optimization strategies