Skip to content

Unrecognized database schema version is treated as a pre-2.0 database #496

Closed

Description

@tonygermano

Summary

If SCHEMA_INFO holds a version string the server doesn't know, such as one written by a newer or different release, ServerMigrator treats the database as schema version 0 and starts running the legacy pre-2.0 migrations against it. Startup then fails with an error about a 2.x-era delta script, which says nothing about the real problem.

Steps to reproduce

With the default Derby database, from the server's install directory:

  1. Start a fresh install once so the database is created, then stop it (Ctrl+C once startup has finished):
    ./oieserver
  2. With the server stopped, set a version this release doesn't know:
    java -cp 'server-lib/database/*' org.apache.derby.tools.ij <<'EOF'
    connect 'jdbc:derby:appdata/mirthdb';
    UPDATE SCHEMA_INFO SET VERSION = '99.0.0';
    SELECT * FROM SCHEMA_INFO;
    exit;
    EOF
  3. Start the server again:
    ./oieserver

On other databases, run the same UPDATE with that database's client.

After the failed start, the process keeps running instead of exiting, which is a separate bug. Stop it with Ctrl+C. On Derby that also hangs, so you'll need kill -9.

Expected

Startup stops with an error naming the unrecognized version, and no migrations run.

Actual

ServerMigrator.migrate() starts the migration chain at V0 and runs LegacyMigrator(1), which executes the first legacy delta script (derby-0-1.sql, postgres-0-1.sql and so on). Startup fails with Failed to execute script for that file.

On a stock schema the script fails at its first statement, DROP TABLE TRANSPORT, because that table no longer exists, so nothing is changed. Nothing guards the path, though: the scripts run with auto-commit on, so if a TRANSPORT table did exist, it would be dropped and the next statements would alter existing tables (CHANNEL, or EVENT on MySQL) before anything failed.

Cause

ServerMigrator.getCurrentVersion() returns Version.fromString() of the stored value, which is null for any string not in the Version enum. migrate() uses null to mean an empty SCHEMA_INFO table and starts from Version.values()[0]. updateVersion() uses the same null to choose INSERT over UPDATE, so a migration step that did succeed would add a second row to SCHEMA_INFO instead of updating the first.

Fix

getCurrentVersion() throws a MigrationException when SCHEMA_INFO has a row whose version isn't recognized, naming the version found. An empty table still starts at V0, as before. Startup already stops on that exception before any other migration runs.

Related


🤖 Drafted with Claude Code

Activity

  1. added 2 commits that reference this issue on Oct 17, 2026
    1d8a682
    bd03dc7
  2. added this to the Next Release milestone on Oct 18, 2026
  3. added a commit that references this issue on Oct 29, 2026
    0089f9f
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

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions