{"record":{"id":"9a648e85fb898947","repo":"Sonarr/Sonarr","slug":"seriesid-or-episodeids-must-be-provided","errorCode":null,"errorMessage":"seriesId or episodeIds must be provided","messagePattern":"seriesId or episodeIds must be provided","errorType":"http","errorClass":"BadRequestException","httpStatus":400,"severity":"warning","filePath":"src/Sonarr.Api.V3/Episodes/EpisodeController.cs","lineNumber":48,"sourceCode":"            if (seriesId.HasValue)\n            {\n                if (seasonNumber.HasValue)\n                {\n                    return MapToResource(_episodeService.GetEpisodesBySeason(seriesId.Value, seasonNumber.Value), includeSeries, includeEpisodeFile, includeImages);\n                }\n\n                return MapToResource(_episodeService.GetEpisodeBySeries(seriesId.Value), includeSeries, includeEpisodeFile, includeImages);\n            }\n            else if (episodeIds.Any())\n            {\n                return MapToResource(_episodeService.GetEpisodes(episodeIds), includeSeries, includeEpisodeFile, includeImages);\n            }\n            else if (episodeFileId.HasValue)\n            {\n                return MapToResource(_episodeService.GetEpisodesByFileId(episodeFileId.Value), includeSeries, includeEpisodeFile, includeImages);\n            }\n\n            throw new BadRequestException(\"seriesId or episodeIds must be provided\");\n        }\n\n        [RestPutById]\n        [Consumes(\"application/json\")]\n        public ActionResult<EpisodeResource> SetEpisodeMonitored([FromRoute] int id, [FromBody] EpisodeResource resource)\n        {\n            _episodeService.SetEpisodeMonitored(id, resource.Monitored);\n\n            resource = MapToResource(_episodeService.GetEpisode(id), false, false, false);\n\n            return Accepted(resource);\n        }\n\n        [HttpPut(\"monitor\")]\n        [Consumes(\"application/json\")]\n        public IActionResult SetEpisodesMonitored([FromBody] EpisodesMonitoredResource resource, [FromQuery] bool includeImages = false)\n        {\n            if (resource.EpisodeIds.Count == 1)","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/Sonarr/Sonarr/blob/da2284d7eaab22ed9b2ca698af690148d691e967/src/Sonarr.Api.V3/Episodes/EpisodeController.cs#L30-L66","documentation":"Returned by GET /api/v3/episode when none of seriesId, episodeIds, or episodeFileId are supplied. The endpoint requires a scope to query episodes; with no scope it falls through every conditional branch and throws BadRequestException (HTTP 400). It prevents an expensive unbounded episode query.","triggerScenarios":"GET /api/v3/episode with an empty query string, or with parameters that don't match any of the three supported filter names. Sending episodeIds=[] alongside no seriesId also reaches this throw.","commonSituations":"A client defaulting all filters to null/empty on initial load; a typo in a query parameter name (e.g. episodeId instead of episodeIds); an integration test hitting the bare endpoint.","solutions":["Supply ?seriesId=<id> for all episodes of a series.","Or ?episodeIds=1&episodeIds=2 for specific episodes.","Or ?episodeFileId=<id> for episodes tied to a file.","Validate that at least one filter is non-empty in the client before sending."],"exampleFix":"// before\nfetch('/api/v3/episode')\n\n// after\nfetch('/api/v3/episode?seriesId=' + seriesId)","handlingStrategy":"validation","validationCode":"const params = new URLSearchParams();\nif (seriesId) params.set('seriesId', seriesId);\nif (episodeIds?.length) episodeIds.forEach(id => params.append('episodeIds', id));\nif (episodeFileId) params.set('episodeFileId', episodeFileId);\nif (![...params.keys()].length) throw new Error('seriesId, episodeIds, or episodeFileId required');\nfetch('/api/v3/episode?' + params);","typeGuard":"function hasEpisodeScope(p){ return p.seriesId != null || (Array.isArray(p.episodeIds) && p.episodeIds.length>0) || p.episodeFileId != null; }","tryCatchPattern":null,"preventionTips":["Require exactly one of the three scopes client-side before request.","Double-check query parameter names (episodeIds vs episodeId vs episodeFileId)."],"tags":["api","validation","episodes","query-params"],"backgroundTag":null,"analyzedSha":"da2284d7eaab22ed9b2ca698af690148d691e967","analyzedAt":"2026-08-13T15:53:02.562Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}