Skip to content

Upgrading

git pull && docker compose up -d --build

Schema migrations run automatically at startup — there are no manual migration steps in the normal case. Each runs once, and the database records how far it has got, so an upgrade interrupted part-way carries on at the next start.

Back up DATA_DIR first: there is no downgrade

A backup taken before upgrading is your only rollback point — see Backups & DATA_DIR. Once a newer release has migrated the database, an older release refuses to start on it, and says so in one line in the log:

The database is at schema version 3, but this build of Trobar only knows versions up to 2. ...

To go back, stop the server, restore the backup, then start the older release.

Sections below that need something from you say so up front; a section with no such flag needs nothing.

Tidal refresh tokens are encrypted at rest (2.18.0)

At its first start, Trobar encrypts each person's stored Tidal refresh token with the credential key, the one that already protects the credentials that send plays (credential_key in DATA_DIR, or wherever TROBAR_CREDENTIAL_KEY_FILE points). If there is no key yet, it makes one. Everyone stays linked to Tidal.

  • If the key file can't be used (it is damaged or can't be read), the tokens stay as they were, the log says how many, and every later start tries again. Nobody is unlinked. Until the key works, linking Tidal is refused, and a token Tidal renews during a sync is stored unencrypted until a later start encrypts it.
  • From now on the Tidal links need the key. A database restored without its key, or a lost key, means each person connects Tidal again on their Profile. Back the key up with DATA_DIR, as Backups & DATA_DIR describes.
  • Going back to an older release: it can't read the encrypted tokens, so its Tidal syncs fail. Restore the backup taken before upgrading.

Upgrading from a pre-10001 (root) image

Action needed: a one-time chown, or the app won't start

Only if you're coming from an image old enough to have run as root.

Older images ran as root, so an existing DATA_DIR created by them is owned by root. The current image runs as the unprivileged uid 10001 and can no longer write it — on start you'll see:

PermissionError: '/data/flask_secret_key'

Fix it once:

docker compose down
sudo chown -R 10001:10001 ./data          # bind mount (reference compose default)
# named volume instead:
#   docker run --rm -v <volume>:/data alpine chown -R 10001:10001 /data
docker compose up -d --build

Client compatibility

The server, Android app, desktop app, and Garmin watch app are released independently and tagged separately (vX.Y.Z, vX.Y.Z, vX.Y.Z, vX.Y.Z) — see Release Cycle & Versioning. The sync API is backward-compatible within a major line, so a slightly older client keeps working against a newer server; update clients at your own pace. The Garmin app has no in-watch auto-update (no Connect IQ Store listing yet) — updating means sideloading a newer .prg the same way as the initial install.

Fingerprints need a scan (2.4.x)

Action needed: run a library scan

Nothing here happens on upgrade alone, and device recovery has nothing to match against until it does.

Upgrading does not populate audio fingerprints on its own. The pass that computes them is queued when a library scan completes, so an existing install needs a scan before device recovery has anything to match against — check Administration → Background jobs for provenance_library_fingerprints.

Two things gate it, deliberately:

  • At least one enrolled device. Fingerprints exist to re-identify a device's files after a server rebuild or a re-tag, so an install that syncs nothing skips the work rather than spending hours of CPU on it.
  • An AcoustID key is not required. Computing a fingerprint is local. The key only adds the lookup that recovers an ISRC for poorly-tagged tracks, and that is the only part which talks to the internet.

On a large library the pass is hours of audio decode. It runs in a separate queue lane, so device syncs stay responsive while it works, and it reports live progress.

Integration tokens minted by non-admins are revoked (2.9.0)

Action needed: an admin must mint a replacement token

Only if a token in use was created by a non-admin — those return 401 after this upgrade. Tokens already minted by an admin keep working.

Integration tokens (Profile → Integrations) can now only be created by an admin, and only an admin may hold one. Any token created by a non-admin user on 2.8.0/2.8.1 is revoked during the upgrade and will return 401.

If a Home Assistant instance (or any other integration) stops authenticating after this upgrade, an admin must mint a replacement token and update the integration's configuration. Tokens that were already created by an admin keep working and need no action.

An integration token's owner is re-checked on every use, not just at minting (2.10.0)

Demoting an admin to a regular user now immediately revokes any integration token (Profile → Integrations) they minted while an admin — previously the mint-time admin check was never re-verified, so the token kept working indefinitely after demotion.

If a Home Assistant instance (or other integration) starts returning 401 right after you demote its owner, this is why: mint a fresh token with a still-admin account and update the integration's configuration. No action needed otherwise.

Newly-synced playlists from a personal account now start private, not shared (2.10.0)

Action needed: the owner must click Shared

Only if your household relies on a per-user link (Tidal, Spotify, a Roon profile, a Jellyfin/Emby mapping) reaching everyone automatically. From now on those playlists start private, and nothing does this for you.

A playlist synced from something personal to one household member — a linked Tidal or Spotify account, a Roon profile mapping, or the new per-user Jellyfin/Emby mapping below — now starts private (visible only to its owner and the admin) the first time it's synced, instead of shared with the whole household by default.

This only affects newly-synced playlists going forward; anything already synced before the upgrade keeps whatever sharing state it already has — upgrading does not retroactively privatize your library. If your household already relies on one of these per-user links and expects those playlists to reach everyone automatically, the owner needs to click Shared on the playlist row (Playlists tab) after upgrading — nothing does this for them.

New: mirror playlists to Subsonic/Navidrome, Jellyfin, or Emby (2.10.0)

Three new mirror-target sinks join the existing folder mirror — see Playlists → Mirroring for what each does and its known quirks (notably: Emby reverts the mirrored playlist's comment field a few seconds after every write — its own behavior, outside Trobar's control, and harmless — the name and track list are unaffected). All are opt-in: nothing mirrors anywhere until an admin sets a target's URL/credentials in Administration → Configuration, so upgrading changes nothing on its own.

Also new: mapping individual Trobar users to their own Jellyfin or Emby account (Administration → Configuration), so their personal playlists sync in alongside the household's — same mechanism the existing Roon profile mapping already used. See the sharing-default note above for what happens to those playlists' visibility.

New: request missing albums from Lidarr (2.11.0)

A different kind of sink from the mirrors above: instead of copying a playlist somewhere, "Request missing albums…" (Playlists tab) asks a Lidarr instance to start watching for an album your library doesn't have — monitor-only, Lidarr's own scheduled search finds it later. See Playlists → Requesting missing albums from Lidarr for the full behavior, including the "requested once, ever, not per playlist" dedup and why the button stays disabled on Roon/iTunes playlists.

Opt-in and inert until an admin completes a two-phase setup in Administration → Configuration: connect a URL/API key, then choose a root folder/quality profile/metadata profile from Lidarr's own live lists — so upgrading changes nothing on its own. Once configured, any household member can toggle it on a playlist they can see, same as the mirror buttons — and, deliberately, nothing in Trobar can undo a request already sent; un-toggling only stops future ones. If that's not a household policy you want, leave it unconfigured.

The device picker replaced the per-row buttons (2.12.0)

Adding a playlist or album to a device is now one button everywhere: pick the device in the dialog, then either keep browsing or send straight away. The basket groups what you've staged by device, so you can queue different things for different devices in one pass. No action needed — existing selections and devices are unaffected.

New: mirror health is visible to integrations (2.12.0)

GET /api/integrations/mirrors reports how many playlist mirrors are currently failing, broken down by sink, so a monitoring integration can alert on a mirror target that has gone away instead of it being noticed only in Administration → Playlist mirrors. See the integration API reference. No action needed.

Anything staged in your basket is cleared by this upgrade (2.12.0)

Action needed: re-add anything you had staged

Items staged before upgrading have no device attached and are removed. Selections already sent to a device, and the devices themselves, are untouched.

The basket now remembers which device each item is staged for, so you can queue different things for different devices in one pass instead of two separate basket sessions. Items staged before upgrading have no device attached and are removed by this upgrade — re-add anything you had queued. Nothing else is affected: selections already sent to a device, and the devices themselves, are untouched.

The four mirror buttons collapsed into one picker (2.13.0)

A playlist row's "Mirror to…" / "Mirror to Subsonic…" / "Mirror to Jellyfin…" / "Mirror to Emby…" buttons are now one "Mirror…" button that opens a picker listing only the sinks an admin has configured. Already-mirrored sinks show greyed with a checkmark — click again to turn one off. A playlist mirrored somewhere now shows an icon for each active sink next to its title instead of a same-row action button; the icon turns red if that sink's last write failed. No action needed — every existing mirror keeps mirroring exactly as before, this only changes how you turn one on or off.

Filesystem mirrors move into per-user folders (2.16.0)

The filesystem mirror now writes each playlist into its owner's folder, <mirror folder>/<user>/music/, with an empty mixed/ beside it, and playlists nobody owns into _shared/music/. That is what lets each Kodi profile read only its own user's playlists (Kodi).

Action needed if a player reads the mirror folder. On the first sync after upgrading, every mirror is rewritten into its owner's folder and the old file in the mirror folder itself is removed (only files carrying Trobar's marker; anything else is left alone). Point the player at a user's folder, or at _shared/, instead.

Pairing shows a short code for every device (2.16.0)

Profile → Devices now pairs every device with an 8-character code and its QR code, valid for an hour: Re-pair in app on an existing device, and the dialog after Create device for a DAP, removable storage or a local folder. Regenerate + QR, which showed the device's raw token, is gone.

Action needed for the desktop app. trobar-desktop v0.11.0, the current desktop release, can't read a code. To pair a card or folder with it, choose Older desktop app? Get a config file instead in the code dialog: that issues a new token, shown as a QR code and a downloadable trobar-device.json, and the device's previous token stops working immediately. A desktop release that reads codes will make this step unnecessary. Cards already paired keep working; nothing changes for them until they're paired again.

Pairing codes last 20 minutes (2.17.0)

A pairing code is now valid for 20 minutes, not an hour. A code you made and haven't used is simply made again. Nothing is needed from you.

Playlists match by MusicBrainz recording id; a one-time tag re-read (2.17.0)

Playlist entries now also match on the MusicBrainz recording id: the one a tagger such as MusicBrainz Picard writes into your files, and the one Jellyfin and Navidrome report for a playlist's songs. A song renamed or re-titled on one side still finds its file, as long as both sides carry the id.

Nothing is needed from you. After the upgrade, a background job named mbid_backfill re-reads the tags of every file in the library once, to pick up ids from files scanned before this release; follow it under Administration → Background jobs. It only reads tags (no audio decoding, nothing sent anywhere), and it runs in the same queue lane as a library scan, so the two never overlap. On a large library it takes a while, the first time only. Files without MusicBrainz tags are simply matched the way they were before.

The first library scan reads every file once (2.17.0)

Trobar now records each track's album artist: the file's albumartist tag, or "Various Artists" for an untagged album whose tracks name several artists. It's what the library will group compilations under.

Nothing is needed from you, but expect the first library scan after the upgrade (yours or the scheduled one) to take longer than usual: it opens every file once to read that tag, about as long as a full rescan. Later scans are back to normal. Until that first scan has run, no album is taken for a compilation.

ALAC in .m4a is now transcoded (2.17.0)

An .m4a file can hold lossless ALAC or lossy AAC. Trobar used to copy every .m4a as it was; now the library scan reads which one a file holds, and a device set to an MP3 format gets ALAC transcoded, like FLAC.

Nothing is needed from you. The first library scan after the upgrade opens each .m4a file once to find out. A device set to MP3 that already holds ALAC tracks as .m4a is then sent them again as .mp3: expect those tracks to download once more. The old .m4a files are left on the device: the desktop app offers to delete them as files Trobar no longer expects there, and on Android they stay until you delete them. Devices that take original files are not affected.

New downloads go into album-artist folders (2.17.0)

Music sent to a device from now on is filed under its album artist: Various Artists/Now 42/… for a compilation instead of one folder per performer, and a guest track in its album's folder. Nothing already on a device moves or downloads again: each file keeps the name it was delivered under, and the server records that name for every file a device held before the upgrade. A device that sends its file list (a reinstall, a first pairing with files already on the card) is recognised under either layout.

An album selection includes the album's guest tracks (2.17.0)

An album you selected now also includes its tracks that credit another artist (a featured guest) but are tagged with the album's own album artist. They used to show in the Library as a separate one-track "album" under the guest's name, and weren't part of the selection. Expect those tracks to download once to the devices that select the album. Nothing is removed, and selections of a single performer's tracks on a compilation keep exactly the tracks they have.

The Library groups albums by album artist; an artist selection includes theirs (2.17.0)

The web Library now lists each album under its album artist: a compilation appears once, under Various Artists (or its albumartist tag), with all its tracks, and a guest track sits with the rest of its album. An artist's page shows, under Also appears on, the albums by others that they play on; selecting one of those syncs only their tracks on it. The phone app's library keeps the old grouping for now.

An artist selection now also includes every track of the albums that artist is the album artist of. Selecting "Various Artists" selects every compilation. For an artist you selected before, their guest tracks on their own albums (tracks credited "X feat. Y" on X's album) join the selection: expect those to download once. Nothing is removed.

Going back to 2.16.0 needs the backup (2.17.0)

2.17.0 is the first release that records how far the database has been migrated, and its migrations change the database 2.16.0 knew, including one that records setup as done on an install older than the setup wizard. 2.16.0 predates that record, so it does not refuse a database 2.17.0 has migrated: it doesn't check, and would start on it. To go back to 2.16.0, stop the server and restore the backup taken before upgrading, as the warning at the top of this page says. From 2.17.0 on, an older release refuses a newer database with the one-line message shown there.

OIDC login requires the nonce (2.17.0)

Action needed if you sign in through OIDC with a provider that doesn't return the nonce. OIDC login now requires the identity provider to return the nonce. A provider that doesn't will refuse logins. Standard providers, Authentik included, are not affected.