Skip to content

hosted-0.71.4 image omitted previously shipped database migrations #7422

Description

@timullrich

Summary

A self-hosted linux/amd64 deployment entered a crash loop after a pod was
recreated with an image observed for
nangohq/nango-server:hosted-0.71.4. The image digest
sha256:d4bb9b8ce574bfc497e3c41da3d318edb3d97e5048ca334e402c7ea09d4008de
did not contain four PostgreSQL migration files that had already been applied
by a previously running image of the same version tag.

Knex correctly refused to start against the existing database:

The migration directory is corrupt, the following files are missing:
20260812150000_add_clock_offset_to_user_mfa_factors.cjs,
20260818173000_create_agent_sessions.cjs,
20260819090000_plans_add_audit_trail_capabilities.cjs,
20260819090100_plans_backfill_audit_trail_control_plane.cjs

The error originates from validateMigrationList in Knex and was repeated on
every restart until the deployment was restored to a known-good digest.

Image comparison

All three images identify as linux/amd64, use
packages/server/entrypoint.sh, and were pulled directly from Docker Hub.

Digest Image creation timestamp Four migration files
sha256:399dd5e52854e7f38a1cd57499feabadf255a289b786521c93e70e8c88910681 2026-08-20T08:48:47Z Present; this is the currently pinned known-good image
sha256:d4bb9b8ce574bfc497e3c41da3d318edb3d97e5048ca334e402c7ea09d4008de 2026-08-13T12:03:18Z Missing; this image produced the crash loop
sha256:635404865d4f48c2e6116bff80868613e8d558410ea54b0db33a2182c956de03 2026-08-27T12:32:25Z Present, together with newer migrations

As of 2026-09-06, Docker Hub resolves hosted-0.71.4 to 6354048.... We are
not claiming that this current digest is broken; it has not yet been
qualified against our disposable database copy. The report is about the
observed d4bb9b8... image and the fact that migration contents differed among
images associated with the same version tag.

Reproduction without database access

image='nangohq/nango-server@sha256:d4bb9b8ce574bfc497e3c41da3d318edb3d97e5048ca334e402c7ea09d4008de'

docker run --rm --entrypoint sh "$image" -c '
  base=/app/nango/packages/database/lib/migrations
  for file in \
    20260812150000_add_clock_offset_to_user_mfa_factors.cjs \
    20260818173000_create_agent_sessions.cjs \
    20260819090000_plans_add_audit_trail_capabilities.cjs \
    20260819090100_plans_backfill_audit_trail_control_plane.cjs
  do
    test -f "$base/$file" || echo "missing: $file"
  done
'

The command reports all four files as missing for d4bb9b8... and reports
none missing for 399dd5e... or 6354048....

Expected behavior

An image published for an existing version tag should not omit migrations that
were delivered by another image for that version, because a normal reschedule
can then make an existing self-hosted database impossible to start.

Questions

  1. Was d4bb9b8... intentionally published or associated with
    hosted-0.71.4?
  2. Are hosted-<version> tags expected to be mutable?
  3. Which immutable version/commit reference is recommended for free
    self-hosting?
  4. Can the image release pipeline enforce append-only database migration
    history for an already published application version?

We have mitigated the incident by pinning the known-good digest and requiring
a disposable-database upgrade test before accepting future image changes.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions