Chapter 26Lesson 04220–300 min

Database and Instance Migration: OrientDB Sunset, H2/PostgreSQL Paths, and Migrator Workflows: Diagnostics, Failure Modes, Security, and Performance

Migration failures are rarely solved by retrying the same command with broader privileges. Diagnose from the compatibility boundary inward: source/target versions, tool version, Java, PostgreSQL ownership/extensions/schema, blob mappings, migration logs, rebuild tasks, and independent content evidence. Preserve the source until the cause is understood.

DiagnosticsMigration logsPostgreSQL failuresBlob mismatchEvidence-first repair

Learning objectives

  • Diagnose source/target/tool/Java compatibility failures before touching data.
  • Interpret PostgreSQL ownership, extension, schema, connectivity, and capacity failures without granting excessive privileges.
  • Separate metadata-count success from blob/content/checksum integrity.
  • Recognize incomplete post-migration rebuilds and target-specific Instance Migrator exclusions.
  • Apply the least-destructive correction while maintaining a tested rollback path.
Dated baseline (27 August 2026). Modern examples use Nexus Repository 3.95.2-01 with Java 21 as the target/reference line. Legacy OrientDB migration examples intentionally pin the source to the final supported OrientDB line, 3.70.5, and do not pretend that 3.95.x can open an OrientDB data directory.
Tool boundary. Database Migrator changes the database backing a self-hosted deployment and requires Nexus to be shut down; it does not move repository blob content. Instance Migrator is a separate live source→target tool that migrates configuration plus hosted assets and tracks migration state. Choose the tool from the migration topology, not from familiarity with a command.
Recovery checkpoint first. Before any migration, take and verify a supported backup/recovery set for the source database/configuration and blob stores. Keep the source untouched until the target passes validation. Do not copy database files across incompatible Nexus versions, rewrite rows, edit blob metadata, or downgrade an already-upgraded data directory as a rollback shortcut.

1. Diagnostic sequence for migration incidents

  1. Freeze the failed attempt; preserve logs and exact commands with secrets redacted.
  2. Confirm source Nexus version, database engine, edition, Java runtime, and source health.
  3. Confirm target Nexus/database version and the current Sonatype-supported source→target path.
  4. Confirm the migrator binary/version and the tool choice itself.
  5. Inspect PostgreSQL ownership, pg_trgm, schema/search path, connectivity, free space, and RAM.
  6. Inspect blob-store names/locations and whether the chosen tool moves blob content.
  7. Inspect migration state/logs and post-migration task history.
  8. Compare repository/security counts and independently verify critical asset SHA-256.
  9. Apply the smallest supported correction.
  10. Re-run validation before considering cutover.

2. Failure: OrientDB source was upgraded past the migration line

Symptom: an operator tries to start a 3.90+/3.95 binary against legacy OrientDB data or has no supported running 3.70.x source.

Cause: Nexus 3.71.0 and later do not support OrientDB. A legacy source must remain on the final 3.70.5 line for current migration workflows.

Correction: stop. Restore/reconstruct the supported 3.70.5 source from a verified pre-upgrade recovery set, using the Java version appropriate to that legacy line, then execute the current migration path. Do not downgrade an already-upgraded modern data directory.

3. Failure: PostgreSQL user can connect but is not the database owner

Symptom: migration/startup may reach the database but schema changes or upgrades fail with permissions/ownership errors.

SELECT current_user,
       pg_get_userbyid(datdba) AS database_owner
FROM pg_database
WHERE datname = current_database();

Correction: have the DBA provision ownership according to Sonatype requirements. Do not “fix” the incident by making the application user a PostgreSQL superuser.

4. Failure: pg_trgm is missing

Symptom: startup/upgrade/migration behavior reports missing trigram functions/extension or fails during schema work.

SELECT extname, extversion, extnamespace::regnamespace
FROM pg_extension
WHERE extname='pg_trgm';

Correction: install the required extension in the intended schema as the supported database owner before proceeding, then re-run the preflight. Do not ignore the failure and hope a later upgrade creates it.

5. Failure: schema exists but the Nexus user cannot create/use objects

Current migration guidance requires suitable CREATE/USAGE permissions and correct currentSchema/search-path behavior when using a non-default schema. Verify both the JDBC URL and database grants. A typo in currentSchema can resemble an empty or incorrectly provisioned target.

6. Failure: migrator fills disk or exhausts memory

Symptom: JVM OOM, temp extraction failure, filesystem nearly full, or migration aborts during extraction/transformation.

Cause: preflight did not reserve the documented RAM and temporary disk headroom. Database migration can require backup + extracted/transformed copies simultaneously.

Correction: preserve the failed logs, free/provision dedicated capacity, verify the source remains healthy, and restart only after the resource gate passes. Do not delete unknown files from $data-dir/db to “make space.”

7. Failure: counts match, downloads return 404 or missing blob

Symptom: repository/component counts look correct but clients cannot fetch some assets.

Cause: Database Migrator moved metadata, not blob content; or target repository→blob mapping points at the wrong location/name.

# Fixture diagnosis: metadata row exists, but target blob is absent.
from pathlib import Path
import json
root=Path('ch26-lab')
state=json.loads((root/'target/db/state.json').read_text())
for a in state['assets']:
    p=root/'target/blobs'/a['path']
    print(a['path'], 'OK' if p.exists() else 'MISSING')

Correction: fix the supported storage/mapping plan, restore/migrate the correct content, then validate hashes. Never create fake empty files or edit blob metadata to satisfy counts.

8. Failure: counts and paths match, checksum differs

This is a stronger integrity failure. Preserve both source and target bytes, expected hashes, migration logs, storage-system checksums/version IDs, and the recovery checkpoint. Reject cutover. Determine whether the copy was corrupt, the source evidence was stale, or a post-migration write changed the coordinate. Do not redefine the expected checksum to match the target.

9. Failure: content exists but browse/search appears incomplete

After database migration Nexus may run browse/search/index normalization tasks; some formats need additional metadata rebuilds. Check task history/log state before assuming data loss. A repository can serve bytes while derived browse/search state is still rebuilding. The correction is usually to let the documented task complete or run the format-specific supported rebuild—not to manipulate database tables.

10. Failure: Instance Migrator reports configuration/content gaps

Use nexus-migrator.log, asset-transfers.log, and failed-asset-transfers.log (names from current documentation) plus per-repository migration state. Distinguish a retryable asset transfer from a documented exclusion. For example, current target-specific migration guidance notes that some external identity configuration must be recreated manually and some generated format metadata is rebuilt rather than copied.

11. Failure: migrated target cannot authenticate to upstream/object storage

If the source migrator cipher was not configured for a supported secret category, the target may intentionally lack the secret. Do not extract or print the old encrypted value. Reconfigure the target credential from the organization’s secret system, then perform a narrowly scoped connectivity test. Redact authentication headers and tokens from evidence.

12. Failure: operator cancels mid-migration and assumes atomic rollback

Database Migrator and Instance Migrator have different state models. An interrupted live transfer may have a partially populated target with resumable state; an interrupted offline database transformation may need a clean restart from the preserved source/backup according to current documentation. Do not improvise by mixing partially migrated database files with a different blob snapshot.

13. Intentionally broken fixture

from pathlib import Path
import json, hashlib
root=Path('ch26-broken')
(root/'target/db').mkdir(parents=True,exist_ok=True)
(root/'target/blobs/pkg').mkdir(parents=True,exist_ok=True)
expected=hashlib.sha256(b'GOOD\n').hexdigest()
(root/'target/db/state.json').write_text(json.dumps({'assets':[{'path':'pkg/a.bin','sha256':expected}]},indent=2))
(root/'target/blobs/pkg/a.bin').write_bytes(b'CORRUPT\n')
state=json.loads((root/'target/db/state.json').read_text())
for a in state['assets']:
 p=root/'target/blobs'/a['path']
 actual=hashlib.sha256(p.read_bytes()).hexdigest()
 print(a['path'], 'PASS' if actual==a['sha256'] else 'CHECKSUM_MISMATCH')

The only acceptable outcome is CHECKSUM_MISMATCH. The repair is to recover/retransfer the known-good byte sequence from the trusted source/backup, not to update the database’s expected hash to the corrupt target.

14. Performance diagnosis: measure the bottleneck before tuning

Migration time can be dominated by source DB read, temp-disk IO, PostgreSQL ingest/WAL/autovacuum, blob transfer throughput, object-store latency, network bandwidth, or post-migration index rebuilds. Capture phase timings and rates. Blindly raising JVM heap or transfer parallelism can increase contention or memory pressure.

Phase Evidence Typical bottleneck
DB transform migrator logs, disk throughput, CPU temp IO / database size
PostgreSQL load DB metrics, WAL, locks, disk DB IO / configuration
Instance asset transfer asset transfer logs, bytes/sec network/blob IO
Post-migration rebuild Nexus task history/logs DB + blob IO / CPU

15. Migration incident evidence packet

  • source/target Nexus versions and Java runtimes;
  • source/target database engines and PostgreSQL ownership/extension/schema evidence;
  • migrator tool/version and redacted command/config;
  • backup/recovery-point identifier;
  • blob-store names/types/locations;
  • migration logs and post-migration task history;
  • repository/component/asset count comparison;
  • critical asset SHA-256 comparison;
  • authorization/client test results;
  • decision: retry, correct precondition, rollback, or escalate.

16. Knowledge check

A PostgreSQL user can connect but is not database owner. Is that acceptable?

Why can browse/search failure after migration be different from content loss?

What should you do when asset counts match but one SHA-256 differs?

Why should you not grant PostgreSQL superuser to fix a schema error?

What is the first action after a migration failure?

17. Summary and bridge

Migration diagnostics now follow evidence instead of folklore: verify the path and preconditions, then database, blobs, logs/tasks, hashes, and clients. Lesson 5 integrates the chapter into a full side-by-side migration drill with prediction, cutover, validation, and rollback evidence.

Official references and version notes

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0 Send only Ethereum/ERC-20 compatible assets to this address.