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.

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.

Appendix: 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)