Sync leaves dangling FK reference when the FK target column is dropped → `Missing ::desired-alias->escaped for "<col>"` crash on query
Summary
When a column that is the target of a foreign-key relationship is dropped from the database, Metabase's sync correctly removes the dead column from the target table's field list, but it leaves the orphaned fk_target reference on the referencing field. Any subsequent query that engages that FK (explicit join, or implicit join via "Display values") crashes in the query compiler with a low-level Clojure exception:
ERROR middleware.catch-exceptions :: Error processing query:
Missing ::desired-alias->escaped for "h_id"
The user-facing message is opaque and gives no indication that the cause is stale FK metadata. The sync step should reconcile FK edges whose target field no longer exists and either drop the relationship or invalidate it, rather than leaving a ticking bomb that detonates at query time.
Steps to reproduce
- Two tables where table
Ahas a field with a foreign key toB.target_col(defined either as a real PG FK constraint, or as a manual FK relationship in Metabase's table metadata). - Let Metabase sync so it records the relationship — the field on
Anow carriesfk_target→B.target_col. - Outside Metabase, drop the target column:
ALTER TABLE b DROP COLUMN target_col; - Trigger a Metabase schema sync / field-values rescan on the database.
- In the Metabase UI, query table
Ain a way that exercises the FK — e.g. a notebook query joiningA→B, or simply having theAfield's Display values set to use the related table.
Expected behavior
After the post-drop sync, Metabase recognizes that B.target_col no longer exists and either:
- removes the
fk_targetfrom theAfield (treating it as a plain scalar), or - surfaces a clear admin warning that an FK relationship is broken and needs attention,
…and in any case does not crash when the table is queried.
Actual behavior
- The sync quietly removes
target_colfromB's own field list (verified: the column is gone frommetabase://table/<B-id>/fields), but theAfield still exposesfk_target_fully_qualified_name = B.target_col. - Querying
AthrowsMissing ::desired-alias->escaped for "target_col"and the query fails entirely. - The only recovery path is manual: open the
Afield in the admin UI and either clear the FK relationship or set Display values → "Original values" to stop the implicit join from being dereferenced.
Observed in production
Hit on noris network Metabase v1.63.10 (self-hosted, PostgreSQL backend). A cube table's integer field retained fk_target → <parent_table>.h_id after a maintenance migration ran ALTER TABLE <parent_table> DROP COLUMN "h_id". Confirming the mechanism: setting the field's Display values to "Original values" immediately resolved the crash, proving the trigger is the implicit-join path dereferencing the dead fk_target.
Diagnostic evidence
GET /api/table/<A-id>/query_metadata for the affected table shows the referencing field still carrying:
{
"id": "<referencing-field-id>",
"name": "<referencing-field-name>",
"fk_target": ["<parent-schema>", "<parent-table>", "h_id"]
}
while the same metadata for the parent table no longer lists h_id among its fields — i.e. the two halves of the relationship are inconsistent after sync.
Suggested fix
During sync, after reconciling each table's columns, walk all known fk_target references and invalidate/drop any whose target field id no longer resolves to a live field. Bonus: if a query still somehow reaches a dangling FK target at compile time, fail with a user-meaningful message ("foreign key target column '' no longer exists on table ''; clear the relationship in Table metadata") instead of Missing ::desired-alias->escaped.
Environment
- Metabase version: v1.63.10
- Database: PostgreSQL
- Deployment: self-hosted
Source: metabase/metabase