{"record":{"id":"d068c70b00b0df76","repo":"Kareadita/Kavita","slug":"bad-payload-from-scrobble-provider","errorCode":null,"errorMessage":"Bad payload from Scrobble Provider","messagePattern":"Bad payload from Scrobble Provider","errorType":"exception","errorClass":"KavitaException","httpStatus":500,"severity":"error","filePath":"Kavita.Services/Plus/ScrobblingService.cs","lineNumber":1674,"sourceCode":"\n                throw new KavitaException(RateLimitHitErrorMessage);\n            }\n\n            _logger.LogError(ex, \"Scrobbling to Kavita+ API failed due to error: {ErrorMessage}\", ex.Message);\n            if (ex.StatusCode == 500 || ex.Message.Contains(\"Call failed with status code 500 (Internal Server Error)\"))\n            {\n                if (!await _unitOfWork.ScrobbleRepository.HasErrorForSeries(evt.SeriesId))\n                {\n                    _unitOfWork.ScrobbleRepository.Attach(new ScrobbleError()\n                    {\n                        Comment = UnknownSeriesErrorMessage,\n                        Details = data.SeriesName,\n                        LibraryId = evt.LibraryId,\n                        SeriesId = evt.SeriesId\n                    });\n                }\n                evt.SetErrorMessage(BadPayLoadErrorMessage);\n                throw new KavitaException(BadPayLoadErrorMessage);\n            }\n            throw;\n        }\n    }\n\n    #endregion\n\n    #region BackFill\n\n    [DisableConcurrentExecution(60 * 60 * 60)]\n    public async Task CreateEventsFromExistingHistory(List<ScrobbleProvider> scrobbleProviders, int userId, CancellationToken ct = default)\n    {\n        foreach (var scrobbleProvider in scrobbleProviders)\n        {\n            await CreateEventsFromExistingHistory(scrobbleProvider, userId, ct);\n        }\n    }\n","sourceCodeStart":1656,"sourceCodeEnd":1692,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/Plus/ScrobblingService.cs#L1656-L1692","documentation":"Thrown in the FlurlHttpException handler when the scrobble POST returns HTTP 500 (Internal Server Error) from the Kavita+ API. Kavita interprets a 500 from Kavita+ as the upstream scrobble provider (MAL/AniList/etc.) rejecting the payload, mapping it to BadPayLoadErrorMessage = 'Bad payload from Scrobble Provider'. It first records a ScrobbleError (Comment = UnknownSeriesErrorMessage) so the series is flagged in the UI and won't keep retrying.","triggerScenarios":"The Kavita+ API forwards a provider-side failure as 500; the payload references a series/mapping the external provider cannot resolve; a malformed or stale external ID was stored for the series; the provider rate-limited with a 500-shaped response.","commonSituations":"A series was matched to the wrong external provider entry; the provider changed its payload schema after an upgrade; metadata for a series was edited to an invalid ID; a deleted-then-readded series kept a stale external mapping.","solutions":["Open the series in the UI; the ScrobbleError flag (UnknownSeriesErrorMessage) marks it — re-match or unmatch the external provider link for that series.","Verify the external provider integration is healthy (valid token, provider not down) in Settings > Scrobbling.","Clear the stale external ID/mapping for the affected series and let Kavita re-match.","Update Kavita to the latest version in case a payload-format bug was fixed."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Reject events whose external mapping is missing/invalid before posting\nvar hasMapping = await _unitOfWork.SeriesRepository.HasExternalMatchAsync(evt.SeriesId);\nif (!hasMapping)\n{\n    _unitOfWork.ScrobbleRepository.Attach(new ScrobbleError { Comment = UnknownSeriesErrorMessage, SeriesId = evt.SeriesId });\n    return; // skip instead of letting the API 500\n}","typeGuard":null,"tryCatchPattern":"try { await scrobblingService.Scrobble(evt); }\ncatch (KavitaException ex) when (ex.Message == \"Bad payload from Scrobble Provider\")\n{\n    _logger.LogWarning(\"Series {Id} rejected by upstream; flagged for re-match\", evt.SeriesId);\n    // ScrobbleError already attached; surface a 're-match this series' hint to the user\n}","preventionTips":["Re-match series to external providers cleanly and avoid stale external IDs.","After upgrades, re-run matching for series that start failing.","Treat a 500 from Kavita+ as a provider rejection, not a transient fault — don't infinite-retry.","Surface flagged series in the UI so users can correct mappings."],"tags":["scrobbling","kavita-plus","bad-payload","external-service"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}