Kareadita/Kavita · error · KavitaException

profile-does-not-exist

Error message

profile-does-not-exist

What it means

Thrown by UpdateParent when GetUserProfile(userId, dto.Id) returns null — the target reading profile that should be merged into the series' parent profile does not exist for the user. The literal 'profile-does-not-exist' is a localization key surfaced to the UI. UpdateParent deletes the named profile and applies its settings onto the resolved parent profile.

Source

Thrown at Kavita.Services/Reading/ReadingProfileService.cs:41

    public async Task<AppUserReadingProfile> GetReadingProfileForSeries(int userId, int libraryId, int seriesId,
        int? activeDeviceId, bool skipImplicit = false)
    {
        return await unitOfWork.AppUserReadingProfileRepository.GetProfileForSeries(userId, libraryId, seriesId,
            activeDeviceId, skipImplicit);
    }

    public async Task<UserReadingProfileDto> GetReadingProfileDtoForSeries(int userId, int libraryId, int seriesId,
        int? activeDeviceId, bool skipImplicit = false)
    {
        return mapper.Map<UserReadingProfileDto>(await GetReadingProfileForSeries(userId, libraryId, seriesId,
            activeDeviceId, skipImplicit));
    }

    public async Task<UserReadingProfileDto> UpdateParent(int userId, int libraryId, int seriesId,
        UserReadingProfileDto dto, int? activeDeviceId)
    {
        var profile = await unitOfWork.AppUserReadingProfileRepository.GetUserProfile(userId, dto.Id);
        if (profile == null) throw new KavitaException("profile-does-not-exist");

        var parentProfile = await GetReadingProfileForSeries(userId, libraryId, seriesId, activeDeviceId, true);

        UpdateReaderProfileFields(parentProfile, dto, false);
        unitOfWork.AppUserReadingProfileRepository.Update(parentProfile);

        // Delete profile as we'll be using the parent now
        unitOfWork.AppUserReadingProfileRepository.Remove(profile);

        await unitOfWork.CommitAsync();
        return mapper.Map<UserReadingProfileDto>(parentProfile);
    }

    public async Task<UserReadingProfileDto> UpdateReadingProfile(int userId, UserReadingProfileDto dto)
    {
        var profile = await unitOfWork.AppUserReadingProfileRepository.GetUserProfile(userId, dto.Id);
        if (profile == null) throw new KavitaException("profile-does-not-exist");

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Refresh the user's reading profile list and retry with a current profile id.
  2. Verify the profile id belongs to the requesting user and still exists.
  3. Handle the not-found case gracefully in the UI instead of retrying the same stale id.
Defensive patterns

Strategy: validation

Validate before calling

var exists = await unitOfWork.AppUserReadingProfileRepository.GetUserProfile(userId, dto.Id) is not null;
if (!exists) return NotFound("profile-does-not-exist");
await profileService.UpdateParent(userId, libraryId, seriesId, dto, activeDeviceId);

Type guard

public static bool ProfileFound(AppUserReadingProfile? p) => p is not null;

Try / catch

try { await profileService.UpdateParent(userId, libraryId, seriesId, dto, activeDeviceId); }
catch (KavitaException ex) when (ex.Message == "profile-does-not-exist") { return NotFound(); }

Prevention

When it happens

Trigger: Client sends a profile id (dto.Id) that was already deleted, belongs to another user, or never existed; concurrent profile edits deleted it between load and update.

Common situations: UI had a stale profile id after another tab deleted it; profile was reset/cleared; id mismatch after a data migration.

Related errors


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/020794b4daf42fb3. Report an issue: GitHub.