#82558·metabase

Sync leaves dangling FK reference when the FK target column is dropped → `Missing ::desired-alias->escaped for "<col>"` crash on query

Author: laserscoutCreated Sep 16, 2026Updated Sep 17, 2026
LabelsPriority:P2

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

  1. Two tables where table A has a field with a foreign key to B.target_col (defined either as a real PG FK constraint, or as a manual FK relationship in Metabase's table metadata).
  2. Let Metabase sync so it records the relationship — the field on A now carries fk_targetB.target_col.
  3. Outside Metabase, drop the target column:
    ALTER TABLE b DROP COLUMN target_col;
    
  4. Trigger a Metabase schema sync / field-values rescan on the database.
  5. In the Metabase UI, query table A in a way that exercises the FK — e.g. a notebook query joining AB, or simply having the A field'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_target from the A field (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_col from B's own field list (verified: the column is gone from metabase://table/<B-id>/fields), but the A field still exposes fk_target_fully_qualified_name = B.target_col.
  • Querying A throws Missing ::desired-alias->escaped for "target_col" and the query fails entirely.
  • The only recovery path is manual: open the A field 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