navidrome/model
Deluan Quintão 3f4b6a642c
fix(server): return 404 instead of 500 for missing native API resources (#6131)
* fix: return 404 instead of 500 for missing native API resources

The deluan/rest controller only maps rest.ErrNotFound to 404, comparing with ==.
Most repositories return model.ErrNotFound, which had the same message but was a
different value, so requesting a missing playlist, album, artist, song, radio,
player, transcoding or library returned 500. This also applied to other users'
private playlists.

Make model.ErrNotFound the same value as rest.ErrNotFound. This fixes every REST
route at once, with no per-route wrapping. errors.Is checks against either
error keep working, and nothing wraps model.ErrNotFound before it reaches the
controller.

Fixes #6130

* fix(radio): return not found when deleting a missing radio station

radioRepository.Delete used the shared delete helper, which never reports a
missing row because SQL DELETE on zero rows is not an error. Deleting an unknown
id silently succeeded: DELETE /api/radio/{id} returned 200, and the Subsonic
deleteInternetRadioStation endpoint returned ok.

Delete now checks the affected row count and returns model.ErrNotFound when
nothing was deleted. The native API returns 404, and deleteInternetRadioStation
returns error 70 (data not found). This matches Subsonic 6.1.6, gonic (both
verified live) and Ampache (verified in source). Airsonic-Advanced does not
implement this endpoint.

The shared delete helper is unchanged, as several callers rely on deletes of
absent rows succeeding.

* fix(ui): return 404 for missing files that are not missing or do not exist

missingRepository.Read filtered media files by bare "id" and "missing" columns.
The media file query joins the library table, so SQLite rejected the query as
ambiguous and GET /api/missing/{id} returned 500. Read now loads the file with
MediaFileRepository.Get, which qualifies the column, and returns not found
when the file does not exist or is not marked missing.

* fix: report missing rows on single-item deletes and adopt deluan/rest errors.Is

Bump github.com/deluan/rest to the version whose controller matches errors
with errors.Is and errors.As. model.ErrNotFound stays the same value as
rest.ErrNotFound, so the many hand-written conversions from model.ErrNotFound
to rest.ErrNotFound in repositories, core services and test mocks did nothing.
Remove them, along with the duplicate rest.ErrNotFound check in the Subsonic
error mapper. Mappings from model.ErrNotAuthorized stay, as those are
different errors.

User and transcoding deletes had the same silent success as radio: the shared
delete helper never reports a missing row, so their not-found checks never
fired and DELETE /api/user/{id} and /api/transcoding/{id} returned 200 for
unknown ids. Add deleteByID, which returns model.ErrNotFound when no row
matched, and use it for radio, user and transcoding. Also drop the dead
sql.ErrNoRows branch from delete, since a DELETE never returns it.

The Subsonic deleteUser endpoint is not implemented (501), so this does not
change the Subsonic API. Plugin deletes keep the silent helper: there is no
REST route for them, and the plugin manager only deletes rows it just read.

* chore: drop ErrNotFound comment and its identity test

The alias to rest.ErrNotFound is self-explanatory, and the identity test only
restated the declaration.

* refactor: alias model.ErrNotAuthorized to rest.ErrPermissionDenied

Like ErrNotFound, make model.ErrNotAuthorized the same value as the rest
library's error, so REST endpoints map it to 403 directly. This removes the
ErrNotAuthorized to rest.ErrPermissionDenied mappings in the library and
playlist REST adapters and the duplicate check in the Subsonic error mapper.

Handlers that check model.ErrNotAuthorized now also recognize
rest.ErrPermissionDenied returned by repositories, so writePlaylistError, the
image upload handlers and the public share handler return 403 for it instead
of their fallback status. The error message changes from "not authorized" to
"permission denied".
2026-09-14 22:46:21 -04:00
..
criteria feat(smartplaylist): add album-level fields for sorting and filtering (#5899) 2026-08-06 10:59:50 -04:00
id refactor(db): migrate all ids to a uniform canonical 128-bit base62 encoding (#5824) 2026-08-02 12:58:53 -04:00
metadata fix: assorted scanner, plugin, and server fixes from the Go 1.27 work (#6050) 2026-08-30 21:24:50 -04:00
request fix(plugins): build public URLs on the caller's address instead of localhost (#6059) 2026-08-31 21:27:43 -04:00
album.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
album_test.go fix(subsonic): avoid double brackets when appending subtitle or version (#5832) 2026-07-20 21:49:14 -04:00
annotation.go feat(subsonic): Add avgRating from subsonic spec (#4900) 2026-01-18 17:42:42 -05:00
artist.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
artist_info.go Get Similar Artists in parallel 2020-10-21 21:44:03 -04:00
artist_test.go refactor(conf): replace eager dir creation with lazy Dir type (#5495) 2026-05-13 17:44:22 -03:00
artwork.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
artwork_id.go feat(cli): add artwork cancel to call off queued artwork work (#6006) 2026-08-21 14:03:59 -04:00
artwork_id_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
artwork_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
bookmark.go Use structs lib to map models to DB. Fix #1266 2021-08-01 12:04:45 -04:00
datastore.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
errors.go fix(server): return 404 instead of 500 for missing native API resources (#6131) 2026-09-14 22:46:21 -04:00
file_types.go Fix M3U mimetype on Debian Bullseye 2024-05-09 22:26:15 -04:00
file_types_test.go Refactor file type functions 2022-12-28 15:31:56 -05:00
folder.go fix(artwork): re-resolve artwork when image files change on disk (#5965) 2026-08-16 13:24:07 -04:00
folder_test.go ci: run Go tests on Windows (#5380) 2026-04-19 13:16:47 -04:00
genre.go fix(jellyfin): resolve genre id as a MusicGenre item 2026-08-10 21:37:57 -04:00
get_entity.go feat(cli): let artwork explain/refresh accept an id without its kind (#5988) 2026-08-19 16:25:12 -04:00
get_entity_test.go feat(cli): let artwork explain/refresh accept an id without its kind (#5988) 2026-08-19 16:25:12 -04:00
image.go refactor(conf): replace eager dir creation with lazy Dir type (#5495) 2026-05-13 17:44:22 -03:00
library.go fix(nativeapi): stop partial PUTs from clearing untouched columns (#6058) 2026-08-31 11:21:32 -04:00
lyrics.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
lyrics_benchmark_test.go fix(scanner): stop logging expected lyrics sniff misses as warnings (#5702) 2026-07-02 09:46:57 -04:00
lyrics_lrc.go feat(lyrics): support [bg:] tag and skip unknown tags in LRC files (#5966) 2026-08-16 10:18:10 -04:00
lyrics_lrc_test.go feat(lyrics): support [bg:] tag and skip unknown tags in LRC files (#5966) 2026-08-16 10:18:10 -04:00
lyrics_lyricsfile.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
lyrics_lyricsfile_test.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
lyrics_normalize.go fix(lyrics): correct TTML background-vocal cue timing and whitespace (#5672) 2026-06-27 10:37:25 -04:00
lyrics_normalize_test.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
lyrics_parse.go fix(scanner): stop logging expected lyrics sniff misses as warnings (#5702) 2026-07-02 09:46:57 -04:00
lyrics_parse_test.go fix(scanner): stop logging expected lyrics sniff misses as warnings (#5702) 2026-07-02 09:46:57 -04:00
lyrics_srt.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
lyrics_srt_test.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
lyrics_test.go refactor(lyrics): single ParseLyrics entry point + all-format plugin lyrics (#5632) 2026-06-19 18:25:35 -04:00
lyrics_ttml.go fix(lyrics): correct TTML background-vocal cue timing and whitespace (#5672) 2026-06-27 10:37:25 -04:00
lyrics_ttml_test.go fix(lyrics): correct TTML background-vocal cue timing and whitespace (#5672) 2026-06-27 10:37:25 -04:00
mediafile.go feat(cli): add missing file list and remap subcommands (#5928) 2026-09-12 12:08:25 -04:00
mediafile_internal_test.go feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709) 2025-02-19 20:35:17 -05:00
mediafile_test.go fix(scanner): keep album tag order from the files instead of alphabetical (#5872) 2026-08-25 10:58:58 -04:00
model_suite_test.go Rename log.LevelCritical to log.LevelFatal 2022-12-21 14:53:36 -05:00
participants.go refactor: replace md5 with xxh3 for faster and more efficient hashing 2026-08-19 09:28:25 -04:00
participants_test.go feat(bfr): Big Refactor: new scanner, lots of new fields and tags, improvements and DB schema changes (#2709) 2025-02-19 20:35:17 -05:00
player.go chore: remove more outdated TODOs 2025-03-23 11:53:43 -04:00
playlist.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
playlist_test.go fix(playlist): block track edits on synced playlists across all APIs (#5984) 2026-08-19 08:47:53 -04:00
playqueue.go feat(server): add update and clear play queue endpoints to native API (#4215) 2025-06-11 12:02:31 -04:00
plugin.go fix(plugins): clear plugin errors on startup to allow retrying 2026-03-02 08:56:56 -05:00
properties.go Associate main entities with library 2024-05-12 21:37:42 -04:00
radio.go fix(artwork): never retry absent artwork on its own (#6054) 2026-09-01 20:48:41 -04:00
radio_test.go feat(artwork): new artwork pipeline with background resolution and Low Quality Image Placeholders (#5847) 2026-08-09 15:03:27 -04:00
scanner.go fix(cli): accept absolute paths in selective scan --target (#5947) 2026-08-12 14:55:04 -04:00
scanner_test.go feat(scanner): implement selective folder scanning and file system watcher improvements (#4674) 2025-11-14 22:15:43 -05:00
scrobble.go feat(server): add scrobble history Native API (#5761) 2026-07-13 11:32:03 -04:00
scrobble_buffer.go fix(plugins): discard buffered scrobbles when a plugin is removed (#5737) 2026-07-08 12:37:17 -04:00
searchable.go feat(subsonic): sort search3 results by relevance (#5086) 2026-02-23 08:51:54 -05:00
share.go fix: miscellaneous fixes for shares, artwork resize, auth limits, and watcher start (#6098) 2026-09-11 15:03:54 -04:00
share_test.go fix: miscellaneous fixes for shares, artwork resize, auth limits, and watcher start (#6098) 2026-09-11 15:03:54 -04:00
tag.go fix(scanner): keep album tag order from the files instead of alphabetical (#5872) 2026-08-25 10:58:58 -04:00
tag_mappings.go feat(scanner): add ArtistSplitExceptions to protect artist names from splitting (#5701) 2026-07-02 08:29:44 -04:00
tag_mappings_test.go feat(scanner): add ArtistSplitExceptions to protect artist names from splitting (#5701) 2026-07-02 08:29:44 -04:00
tag_test.go fix(scanner): keep album tag order from the files instead of alphabetical (#5872) 2026-08-25 10:58:58 -04:00
transcoding.go Replace beego/orm with dbx (#2693) 2023-12-09 13:52:17 -05:00
user.go feat(jellyfin): non-expiring, audience-scoped tokens revocable by password change (#6013) 2026-08-22 20:36:24 -04:00
user_props.go Pass userId explicitly to UserPropsRepository methods 2021-06-25 22:21:37 -04:00
user_test.go feat: Multi-library support (#4181) 2025-07-18 18:41:12 -04:00