Files
unshackle/dev/rest-api/errors/index.html
T
2026-11-03 18:55:03 +00:00

2873 lines
75 KiB
HTML

<!doctype html>
<html lang="en" class="no-js">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="description" content="Movie, TV, and Music archival software. User guide and REST API reference">
<link rel="canonical" href="https://docs.unshackle.dev/dev/rest-api/errors/">
<link rel="prev" href="../remote-sessions/">
<link rel="next" href="../../../reference/api/service/">
<link rel="icon" href="../../../assets/favicon.svg">
<meta name="generator" content="mkdocs-1.6.1, mkdocs-material-9.8.0">
<title>Error Responses - unshackle</title>
<link rel="stylesheet" href="../../../assets/stylesheets/main.57a0d79d.min.css">
<link rel="stylesheet" href="../../../assets/stylesheets/palette.fb2fffe2.min.css">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300i,400,400i,700,700i%7CRoboto+Mono:400,400i,700,700i&display=fallback">
<style>:root{--md-text-font:"Roboto";--md-code-font:"Roboto Mono"}</style>
<link rel="stylesheet" href="../../../assets/_mkdocstrings.css">
<link rel="stylesheet" href="../../../assets/extra.css">
<script>__md_scope=new URL("../../..",location),__md_hash=e=>[...e].reduce(((e,_)=>(e<<5)-e+_.charCodeAt(0)),0),__md_get=(e,_=localStorage,t=__md_scope)=>JSON.parse(_.getItem(t.pathname+"."+e)),__md_set=(e,_,t=localStorage,a=__md_scope)=>{try{t.setItem(a.pathname+"."+e,JSON.stringify(_))}catch(e){}}</script>
</head>
<body dir="ltr" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo">
<input class="md-toggle" data-md-toggle="drawer" type="checkbox" id="__drawer" autocomplete="off">
<input class="md-toggle" data-md-toggle="search" type="checkbox" id="__search" autocomplete="off">
<label class="md-overlay" for="__drawer"></label>
<div data-md-component="skip">
<a href="#error-responses" class="md-skip">
Skip to content
</a>
</div>
<div data-md-component="announce">
</div>
<header class="md-header" data-md-component="header">
<nav class="md-header__inner md-grid" aria-label="Header">
<a href="../../.." title="unshackle" class="md-header__button md-logo" aria-label="unshackle" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m800-274-80-80v-206H514l-80-80h166v-80q0-50-34.5-85T481-840q-50 0-84 34.5T363-720v9l-73-73q22-61 75-98.5T481-920q83 0 141 58.5T680-720v80h40q33 0 56.5 23.5T800-560v286Zm20 246-62-62q-11 5-20 7.5T720-80H240q-33 0-56.5-23.5T160-160v-400q0-25 14.5-46t37.5-30L28-820l56-56L876-84l-56 56ZM686-160 539-309q-11 11-25.5 17t-31.5 6q-33 0-56.5-23.5T402-366q0-17 6-31.5t17-25.5L286-560h-46v400h446ZM486-360Zm131-97Z"/></svg>
</a>
<label class="md-header__button md-icon" for="__drawer">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3 6h18v2H3zm0 5h18v2H3zm0 5h18v2H3z"/></svg>
</label>
<div class="md-header__title" data-md-component="header-title">
<div class="md-header__ellipsis">
<div class="md-header__topic">
<span class="md-ellipsis">
unshackle
</span>
</div>
<div class="md-header__topic" data-md-component="header-topic">
<span class="md-ellipsis">
Error Responses
</span>
</div>
</div>
</div>
<form class="md-header__option" data-md-component="palette">
<input class="md-option" data-md-color-media="(prefers-color-scheme)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_0">
<label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M3.9 12c0-1.71 1.39-3.1 3.1-3.1h4V7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h4v-1.9H7c-1.71 0-3.1-1.39-3.1-3.1M8 13h8v-2H8zm9-6h-4v1.9h4c1.71 0 3.1 1.39 3.1 3.1s-1.39 3.1-3.1 3.1h-4V17h4a5 5 0 0 0 5-5 5 5 0 0 0-5-5"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
<label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5m0 8a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3"/></svg>
</label>
<input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="indigo" aria-label="Switch to system preference" type="radio" name="__palette" id="__palette_2">
<label class="md-header__button md-icon" title="Switch to system preference" for="__palette_0" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M17 7H7a5 5 0 0 0-5 5 5 5 0 0 0 5 5h10a5 5 0 0 0 5-5 5 5 0 0 0-5-5M7 15a3 3 0 0 1-3-3 3 3 0 0 1 3-3 3 3 0 0 1 3 3 3 3 0 0 1-3 3"/></svg>
</label>
</form>
<script>var palette=__md_get("__palette");if(palette&&palette.color){if("(prefers-color-scheme)"===palette.color.media){var media=matchMedia("(prefers-color-scheme: light)"),input=document.querySelector(media.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");palette.color.media=input.getAttribute("data-md-color-media"),palette.color.scheme=input.getAttribute("data-md-color-scheme"),palette.color.primary=input.getAttribute("data-md-color-primary"),palette.color.accent=input.getAttribute("data-md-color-accent")}for(var[key,value]of Object.entries(palette.color))document.body.setAttribute("data-md-color-"+key,value)}</script>
<label class="md-header__button md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
</label>
<div class="md-search" data-md-component="search" role="dialog">
<label class="md-search__overlay" for="__search"></label>
<div class="md-search__inner" role="search">
<form class="md-search__form" name="search">
<input type="text" class="md-search__input" name="query" aria-label="Search" placeholder="Search" autocapitalize="off" autocorrect="off" autocomplete="off" spellcheck="false" data-md-component="search-query" required>
<label class="md-search__icon md-icon" for="__search">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M9.5 3A6.5 6.5 0 0 1 16 9.5c0 1.61-.59 3.09-1.56 4.23l.27.27h.79l5 5-1.5 1.5-5-5v-.79l-.27-.27A6.52 6.52 0 0 1 9.5 16 6.5 6.5 0 0 1 3 9.5 6.5 6.5 0 0 1 9.5 3m0 2C7 5 5 7 5 9.5S7 14 9.5 14 14 12 14 9.5 12 5 9.5 5"/></svg>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</label>
<nav class="md-search__options" aria-label="Search">
<a href="javascript:void(0)" class="md-search__icon md-icon" title="Share" aria-label="Share" data-clipboard data-clipboard-text="" data-md-component="search-share" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M18 16.08c-.76 0-1.44.3-1.96.77L8.91 12.7c.05-.23.09-.46.09-.7s-.04-.47-.09-.7l7.05-4.11c.54.5 1.25.81 2.04.81a3 3 0 0 0 3-3 3 3 0 0 0-3-3 3 3 0 0 0-3 3c0 .24.04.47.09.7L8.04 9.81C7.5 9.31 6.79 9 6 9a3 3 0 0 0-3 3 3 3 0 0 0 3 3c.79 0 1.5-.31 2.04-.81l7.12 4.15c-.05.21-.08.43-.08.66 0 1.61 1.31 2.91 2.92 2.91s2.92-1.3 2.92-2.91A2.92 2.92 0 0 0 18 16.08"/></svg>
</a>
<button type="reset" class="md-search__icon md-icon" title="Clear" aria-label="Clear" tabindex="-1">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M19 6.41 17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>
</button>
</nav>
<div class="md-search__suggest" data-md-component="search-suggest"></div>
</form>
<div class="md-search__output">
<div class="md-search__scrollwrap" tabindex="0" data-md-scrollfix>
<div class="md-search-result" data-md-component="search-result">
<div class="md-search-result__meta">
Initializing search
</div>
<ol class="md-search-result__list" role="presentation"></ol>
</div>
</div>
</div>
</div>
</div>
<div class="md-header__source">
<a href="https://github.com/unshackle-dl/unshackle" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
unshackle-dl/unshackle
</div>
</a>
</div>
</nav>
</header>
<div class="md-container" data-md-component="container">
<nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
<div class="md-grid">
<ul class="md-tabs__list">
<li class="md-tabs__item">
<a href="../../.." class="md-tabs__link">
Home
</a>
</li>
<li class="md-tabs__item">
<a href="../../../getting-started/installation/" class="md-tabs__link">
Getting Started
</a>
</li>
<li class="md-tabs__item">
<a href="../../../guide/downloading/" class="md-tabs__link">
User Guide
</a>
</li>
<li class="md-tabs__item">
<a href="../../../reference/configuration/" class="md-tabs__link">
Configuration
</a>
</li>
<li class="md-tabs__item md-tabs__item--active">
<a href="../../creating-a-service/" class="md-tabs__link">
Developer
</a>
</li>
<li class="md-tabs__item">
<a href="../../../reference/api/service/" class="md-tabs__link">
API Reference
</a>
</li>
</ul>
</div>
</nav>
<main class="md-main" data-md-component="main">
<div class="md-main__inner md-grid">
<div class="md-sidebar md-sidebar--primary" data-md-component="sidebar" data-md-type="navigation" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--primary md-nav--lifted" aria-label="Navigation" data-md-level="0">
<label class="md-nav__title" for="__drawer">
<a href="../../.." title="unshackle" class="md-nav__button md-logo" aria-label="unshackle" data-md-component="logo">
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m800-274-80-80v-206H514l-80-80h166v-80q0-50-34.5-85T481-840q-50 0-84 34.5T363-720v9l-73-73q22-61 75-98.5T481-920q83 0 141 58.5T680-720v80h40q33 0 56.5 23.5T800-560v286Zm20 246-62-62q-11 5-20 7.5T720-80H240q-33 0-56.5-23.5T160-160v-400q0-25 14.5-46t37.5-30L28-820l56-56L876-84l-56 56ZM686-160 539-309q-11 11-25.5 17t-31.5 6q-33 0-56.5-23.5T402-366q0-17 6-31.5t17-25.5L286-560h-46v400h446ZM486-360Zm131-97Z"/></svg>
</a>
unshackle
</label>
<div class="md-nav__source">
<a href="https://github.com/unshackle-dl/unshackle" title="Go to repository" class="md-source" data-md-component="source">
<div class="md-source__icon md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2025 Fonticons, Inc.--><path d="M439.6 236.1 244 40.5c-5.4-5.5-12.8-8.5-20.4-8.5s-15 3-20.4 8.4L162.5 81l51.5 51.5c27.1-9.1 52.7 16.8 43.4 43.7l49.7 49.7c34.2-11.8 61.2 31 35.5 56.7-26.5 26.5-70.2-2.9-56-37.3L240.3 199v121.9c25.3 12.5 22.3 41.8 9.1 55-6.4 6.4-15.2 10.1-24.3 10.1s-17.8-3.6-24.3-10.1c-17.6-17.6-11.1-46.9 11.2-56v-123c-20.8-8.5-24.6-30.7-18.6-45L142.6 101 8.5 235.1C3 240.6 0 247.9 0 255.5s3 15 8.5 20.4l195.6 195.7c5.4 5.4 12.7 8.4 20.4 8.4s15-3 20.4-8.4l194.7-194.7c5.4-5.4 8.4-12.8 8.4-20.4s-3-15-8.4-20.4"/></svg>
</div>
<div class="md-source__repository">
unshackle-dl/unshackle
</div>
</a>
</div>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../.." class="md-nav__link">
<span class="md-ellipsis">
Home
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
<label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
<span class="md-ellipsis">
Getting Started
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_2">
<span class="md-nav__icon md-icon"></span>
Getting Started
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../getting-started/installation/" class="md-nav__link">
<span class="md-ellipsis">
Installation
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../getting-started/quickstart/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../getting-started/configuration-file/" class="md-nav__link">
<span class="md-ellipsis">
The Configuration File
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" >
<label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
<span class="md-ellipsis">
User Guide
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_3">
<span class="md-nav__icon md-icon"></span>
User Guide
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../guide/downloading/" class="md-nav__link">
<span class="md-ellipsis">
Downloading
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/cli-reference/" class="md-nav__link">
<span class="md-ellipsis">
CLI Reference
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/drm-and-cdm/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM Setup
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/proxies-and-vpn/" class="md-nav__link">
<span class="md-ellipsis">
Proxies & VPN
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/vaults/" class="md-nav__link">
<span class="md-ellipsis">
Key Vaults
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/output-and-naming/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/subtitles/" class="md-nav__link">
<span class="md-ellipsis">
Subtitles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../guide/troubleshooting/" class="md-nav__link">
<span class="md-ellipsis">
Troubleshooting
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
<div class="md-nav__link md-nav__container">
<a href="../../../reference/configuration/" class="md-nav__link ">
<span class="md-ellipsis">
Configuration
</span>
</a>
<label class="md-nav__link " for="__nav_4" id="__nav_4_label" tabindex="0">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_4">
<span class="md-nav__icon md-icon"></span>
Configuration
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../reference/configuration/directories/" class="md-nav__link">
<span class="md-ellipsis">
Directories
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/services/" class="md-nav__link">
<span class="md-ellipsis">
Services & Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/download/" class="md-nav__link">
<span class="md-ellipsis">
Download & Processing
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/output/" class="md-nav__link">
<span class="md-ellipsis">
Output & Naming
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/drm/" class="md-nav__link">
<span class="md-ellipsis">
DRM & CDM
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/network/" class="md-nav__link">
<span class="md-ellipsis">
Network & Proxy
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/vaults/" class="md-nav__link">
<span class="md-ellipsis">
Key Vaults
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/post-scripts/" class="md-nav__link">
<span class="md-ellipsis">
Post-Scripts
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/misc/" class="md-nav__link">
<span class="md-ellipsis">
Other Settings
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/configuration/example/" class="md-nav__link">
<span class="md-ellipsis">
Annotated Example
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" checked>
<label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="">
<span class="md-ellipsis">
Developer
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_5">
<span class="md-nav__icon md-icon"></span>
Developer
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../creating-a-service/" class="md-nav__link">
<span class="md-ellipsis">
Creating a Service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../service-architecture/" class="md-nav__link">
<span class="md-ellipsis">
Service Architecture
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active md-nav__item--section md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5_3" checked>
<div class="md-nav__link md-nav__container">
<a href="../" class="md-nav__link ">
<span class="md-ellipsis">
REST API
</span>
</a>
<label class="md-nav__link " for="__nav_5_3" id="__nav_5_3_label" tabindex="">
<span class="md-nav__icon md-icon"></span>
</label>
</div>
<nav class="md-nav" data-md-level="2" aria-labelledby="__nav_5_3_label" aria-expanded="true">
<label class="md-nav__title" for="__nav_5_3">
<span class="md-nav__icon md-icon"></span>
REST API
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../quickstart/" class="md-nav__link">
<span class="md-ellipsis">
Quick Start
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../authentication/" class="md-nav__link">
<span class="md-ellipsis">
Authentication
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../endpoints/" class="md-nav__link">
<span class="md-ellipsis">
Endpoints
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../job-lifecycle/" class="md-nav__link">
<span class="md-ellipsis">
Job Lifecycle
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../dashboard/" class="md-nav__link">
<span class="md-ellipsis">
Dashboard
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../remote-sessions/" class="md-nav__link">
<span class="md-ellipsis">
Remote Sessions
</span>
</a>
</li>
<li class="md-nav__item md-nav__item--active">
<input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
<label class="md-nav__link md-nav__link--active" for="__toc">
<span class="md-ellipsis">
Error Responses
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<a href="./" class="md-nav__link md-nav__link--active">
<span class="md-ellipsis">
Error Responses
</span>
</a>
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-standard-error-shape" class="md-nav__link">
<span class="md-ellipsis">
The standard error shape
</span>
</a>
<nav class="md-nav" aria-label="The standard error shape">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#find-an-error-from-its-ref" class="md-nav__link">
<span class="md-ellipsis">
Find an error from its ref
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#the-details-object" class="md-nav__link">
<span class="md-ellipsis">
The details object
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#the-retryable-hint" class="md-nav__link">
<span class="md-ellipsis">
The retryable hint
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#error-code-catalogue" class="md-nav__link">
<span class="md-ellipsis">
Error code catalogue
</span>
</a>
<nav class="md-nav" aria-label="Error code catalogue">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#client-errors-4xx" class="md-nav__link">
<span class="md-ellipsis">
Client errors (4xx)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#server-errors-422-and-424" class="md-nav__link">
<span class="md-ellipsis">
Server errors (422 and 424)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#how-the-server-produces-errors" class="md-nav__link">
<span class="md-ellipsis">
How the server produces errors
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#the-authentication-error-exception" class="md-nav__link">
<span class="md-ellipsis">
The authentication error exception
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#late-failures-with-status-200" class="md-nav__link">
<span class="md-ellipsis">
Late failures with status 200
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#responses-with-no-body" class="md-nav__link">
<span class="md-ellipsis">
Responses with no body
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#debug-information" class="md-nav__link">
<span class="md-ellipsis">
Debug information
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#client-handling-recommendations" class="md-nav__link">
<span class="md-ellipsis">
Client handling recommendations
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item md-nav__item--nested">
<input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
<label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
<span class="md-ellipsis">
API Reference
</span>
<span class="md-nav__icon md-icon"></span>
</label>
<nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
<label class="md-nav__title" for="__nav_6">
<span class="md-nav__icon md-icon"></span>
API Reference
</label>
<ul class="md-nav__list" data-md-scrollfix>
<li class="md-nav__item">
<a href="../../../reference/api/service/" class="md-nav__link">
<span class="md-ellipsis">
Service
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/api/config/" class="md-nav__link">
<span class="md-ellipsis">
Config
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/api/tracks/" class="md-nav__link">
<span class="md-ellipsis">
Tracks
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/api/titles/" class="md-nav__link">
<span class="md-ellipsis">
Titles
</span>
</a>
</li>
<li class="md-nav__item">
<a href="../../../reference/api/drm/" class="md-nav__link">
<span class="md-ellipsis">
DRM
</span>
</a>
</li>
</ul>
</nav>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-sidebar md-sidebar--secondary" data-md-component="sidebar" data-md-type="toc" >
<div class="md-sidebar__scrollwrap">
<div class="md-sidebar__inner">
<nav class="md-nav md-nav--secondary" aria-label="Table of contents">
<label class="md-nav__title" for="__toc">
<span class="md-nav__icon md-icon"></span>
Table of contents
</label>
<ul class="md-nav__list" data-md-component="toc" data-md-scrollfix>
<li class="md-nav__item">
<a href="#the-standard-error-shape" class="md-nav__link">
<span class="md-ellipsis">
The standard error shape
</span>
</a>
<nav class="md-nav" aria-label="The standard error shape">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#find-an-error-from-its-ref" class="md-nav__link">
<span class="md-ellipsis">
Find an error from its ref
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#the-details-object" class="md-nav__link">
<span class="md-ellipsis">
The details object
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#the-retryable-hint" class="md-nav__link">
<span class="md-ellipsis">
The retryable hint
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#error-code-catalogue" class="md-nav__link">
<span class="md-ellipsis">
Error code catalogue
</span>
</a>
<nav class="md-nav" aria-label="Error code catalogue">
<ul class="md-nav__list">
<li class="md-nav__item">
<a href="#client-errors-4xx" class="md-nav__link">
<span class="md-ellipsis">
Client errors (4xx)
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#server-errors-422-and-424" class="md-nav__link">
<span class="md-ellipsis">
Server errors (422 and 424)
</span>
</a>
</li>
</ul>
</nav>
</li>
<li class="md-nav__item">
<a href="#how-the-server-produces-errors" class="md-nav__link">
<span class="md-ellipsis">
How the server produces errors
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#the-authentication-error-exception" class="md-nav__link">
<span class="md-ellipsis">
The authentication error exception
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#late-failures-with-status-200" class="md-nav__link">
<span class="md-ellipsis">
Late failures with status 200
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#responses-with-no-body" class="md-nav__link">
<span class="md-ellipsis">
Responses with no body
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#debug-information" class="md-nav__link">
<span class="md-ellipsis">
Debug information
</span>
</a>
</li>
<li class="md-nav__item">
<a href="#client-handling-recommendations" class="md-nav__link">
<span class="md-ellipsis">
Client handling recommendations
</span>
</a>
</li>
</ul>
</nav>
</div>
</div>
</div>
<div class="md-content" data-md-component="content">
<article class="md-content__inner md-typeset">
<h1 id="error-responses">Error Responses<a class="headerlink" href="#error-responses" title="Permanent link">&para;</a></h1>
<p>Every endpoint of the unshackle REST API reports failures in a single, predictable
shape. The cause can be a missing field, a service that refuses to authenticate, or a
download worker that crashed. In each case the server answers with a JSON body
that carries a machine-readable <strong>error code</strong>, a human-readable <strong>message</strong>, and a
matching <strong>HTTP status</strong>. This page documents that format and catalogues every error
code the server can send.</p>
<p>If you write a client against the API, read this page alongside the endpoint
reference. Each endpoint lists the specific codes it raises, and this page gives the
meanings of those codes.</p>
<div class="admonition note">
<p class="admonition-title">Where this comes from</p>
<p><code>unshackle/core/api/errors.py</code> defines the error format, and the wrapper
that turns raised errors into responses lives in <code>unshackle/core/api/routes.py</code>.
Nothing on this page is invented. It reflects the actual server behaviour.</p>
</div>
<h2 id="the-standard-error-shape">The standard error shape<a class="headerlink" href="#the-standard-error-shape" title="Permanent link">&para;</a></h2>
<p>A structured error is always a JSON object with <code>status</code> set to the literal string
<code>"error"</code>. The full set of fields:</p>
<div class="language-json highlight"><span class="filename">Error response body</span><pre><span></span><code><span id="__span-0-1"><a id="__codelineno-0-1" name="__codelineno-0-1" href="#__codelineno-0-1"></a><span class="p">{</span>
</span><span id="__span-0-2"><a id="__codelineno-0-2" name="__codelineno-0-2" href="#__codelineno-0-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"error"</span><span class="p">,</span>
</span><span id="__span-0-3"><a id="__codelineno-0-3" name="__codelineno-0-3" href="#__codelineno-0-3"></a><span class="w"> </span><span class="nt">"error_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"INVALID_PARAMETERS"</span><span class="p">,</span>
</span><span id="__span-0-4"><a id="__codelineno-0-4" name="__codelineno-0-4" href="#__codelineno-0-4"></a><span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"vcodec must be one of: H264, H265, ... (ref 7f3a2c)"</span><span class="p">,</span>
</span><span id="__span-0-5"><a id="__codelineno-0-5" name="__codelineno-0-5" href="#__codelineno-0-5"></a><span class="w"> </span><span class="nt">"ref"</span><span class="p">:</span><span class="w"> </span><span class="s2">"7f3a2c"</span><span class="p">,</span>
</span><span id="__span-0-6"><a id="__codelineno-0-6" name="__codelineno-0-6" href="#__codelineno-0-6"></a><span class="w"> </span><span class="nt">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-07-03T12:34:56.789012+00:00"</span><span class="p">,</span>
</span><span id="__span-0-7"><a id="__codelineno-0-7" name="__codelineno-0-7" href="#__codelineno-0-7"></a><span class="w"> </span><span class="nt">"details"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">"field"</span><span class="p">:</span><span class="w"> </span><span class="s2">"vcodec"</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-0-8"><a id="__codelineno-0-8" name="__codelineno-0-8" href="#__codelineno-0-8"></a><span class="w"> </span><span class="nt">"retryable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="p">,</span>
</span><span id="__span-0-9"><a id="__codelineno-0-9" name="__codelineno-0-9" href="#__codelineno-0-9"></a><span class="w"> </span><span class="nt">"debug_info"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-0-10"><a id="__codelineno-0-10" name="__codelineno-0-10" href="#__codelineno-0-10"></a><span class="w"> </span><span class="nt">"exception_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"APIError"</span><span class="p">,</span>
</span><span id="__span-0-11"><a id="__codelineno-0-11" name="__codelineno-0-11" href="#__codelineno-0-11"></a><span class="w"> </span><span class="nt">"traceback"</span><span class="p">:</span><span class="w"> </span><span class="s2">"..."</span>
</span><span id="__span-0-12"><a id="__codelineno-0-12" name="__codelineno-0-12" href="#__codelineno-0-12"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-0-13"><a id="__codelineno-0-13" name="__codelineno-0-13" href="#__codelineno-0-13"></a><span class="p">}</span>
</span></code></pre></div>
<table>
<thead>
<tr>
<th>Field</th>
<th>Type</th>
<th>Always present?</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>status</code></td>
<td>string</td>
<td>Yes</td>
<td>Always the literal <code>"error"</code>. Lets a client distinguish an error body from a success body at a glance.</td>
</tr>
<tr>
<td><code>error_code</code></td>
<td>string</td>
<td>Yes</td>
<td>A stable, machine-readable code from the <a href="#error-code-catalogue">catalogue below</a>. Match on this, not on <code>message</code>.</td>
</tr>
<tr>
<td><code>message</code></td>
<td>string</td>
<td>Yes</td>
<td>A human-readable description of what went wrong, followed by <code>(ref &lt;ref&gt;)</code>. Wording may change between versions, so do not parse it.</td>
</tr>
<tr>
<td><code>ref</code></td>
<td>string</td>
<td>Yes</td>
<td>A short random reference for this one error. The server logs it with the request, so an operator can find the record from a user's report.</td>
</tr>
<tr>
<td><code>timestamp</code></td>
<td>string</td>
<td>Yes</td>
<td>ISO 8601 timestamp (UTC) of when the error response was built.</td>
</tr>
<tr>
<td><code>details</code></td>
<td>object</td>
<td>Only when non-empty</td>
<td>Structured, error-specific context (for example the invalid field, a list of available titles, or the set of currently active jobs).</td>
</tr>
<tr>
<td><code>retryable</code></td>
<td>boolean</td>
<td>Only when <code>true</code></td>
<td>Present and set to <code>true</code> when retrying the same request may succeed later (network blips, rate limiting, transient outages). Absent otherwise.</td>
</tr>
<tr>
<td><code>debug_info</code></td>
<td>object</td>
<td>Only with <code>--debug-api</code></td>
<td>Technical diagnostics; see <a href="#debug-information">Debug information</a>.</td>
</tr>
</tbody>
</table>
<div class="admonition tip">
<p class="admonition-title">Match on <code>error_code</code>, branch on HTTP status</p>
<p>Treat <code>error_code</code> as the primary signal your code reacts to, and the HTTP status
as a coarse fallback for anything you do not recognise. The two are consistent:
every code maps to a default status (see the catalogue), and the pairing is
stable across releases.</p>
</div>
<h3 id="find-an-error-from-its-ref">Find an error from its <code>ref</code><a class="headerlink" href="#find-an-error-from-its-ref" title="Permanent link">&para;</a></h3>
<p>For each error response, the server logs one <code>WARNING</code> line on the <code>api</code> logger:</p>
<div class="language-text highlight"><pre><span></span><code><span id="__span-1-1"><a id="__codelineno-1-1" name="__codelineno-1-1" href="#__codelineno-1-1"></a>Error ref 7f3a2c: SERVICE_ERROR 422 POST /api/session/&lt;id&gt;/license service=EXAMPLE user=alice: Licence request failed: ...
</span></code></pre></div>
<p>Search the server log for <code>Error ref &lt;ref&gt;</code>. The handler's traceback, when there is one,
is directly above that line. The <a href="../dashboard/">developer dashboard</a> log view also shows it.</p>
<h3 id="the-details-object">The <code>details</code> object<a class="headerlink" href="#the-details-object" title="Permanent link">&para;</a></h3>
<p>When present, <code>details</code> carries extra context specific to the error. It is only
included when it is non-empty, so a client must treat a missing <code>details</code> as "no
extra information". Some concrete examples you may encounter:</p>
<ul>
<li>A validation failure may include the offending field or the list of valid values.</li>
<li>A "title not found" error on a remote session includes <code>available_titles</code>.</li>
<li>A maintenance conflict includes <code>active_jobs</code>, the jobs blocking the operation.</li>
<li>Categorised exceptions add a <code>reason</code> tag, such as <code>"network_connectivity"</code> or
<code>"geofence_restriction"</code>.</li>
</ul>
<h3 id="the-retryable-hint">The <code>retryable</code> hint<a class="headerlink" href="#the-retryable-hint" title="Permanent link">&para;</a></h3>
<p>The <code>retryable</code> field appears <strong>only when it is <code>true</code></strong>. It is set for conditions
the server believes are transient: network errors, rate limiting, and temporary
service unavailability. When you see it, you can back off and try the request again.
When it is absent, assume the request will keep failing until you change something.</p>
<div class="admonition example">
<p class="admonition-title">A retryable network error</p>
<div class="language-json highlight"><pre><span></span><code><span id="__span-2-1"><a id="__codelineno-2-1" name="__codelineno-2-1" href="#__codelineno-2-1"></a><span class="p">{</span>
</span><span id="__span-2-2"><a id="__codelineno-2-2" name="__codelineno-2-2" href="#__codelineno-2-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"error"</span><span class="p">,</span>
</span><span id="__span-2-3"><a id="__codelineno-2-3" name="__codelineno-2-3" href="#__codelineno-2-3"></a><span class="w"> </span><span class="nt">"error_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"NETWORK_ERROR"</span><span class="p">,</span>
</span><span id="__span-2-4"><a id="__codelineno-2-4" name="__codelineno-2-4" href="#__codelineno-2-4"></a><span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Network error occurred: Connection timed out"</span><span class="p">,</span>
</span><span id="__span-2-5"><a id="__codelineno-2-5" name="__codelineno-2-5" href="#__codelineno-2-5"></a><span class="w"> </span><span class="nt">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-07-03T12:00:00+00:00"</span><span class="p">,</span>
</span><span id="__span-2-6"><a id="__codelineno-2-6" name="__codelineno-2-6" href="#__codelineno-2-6"></a><span class="w"> </span><span class="nt">"details"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">"reason"</span><span class="p">:</span><span class="w"> </span><span class="s2">"network_connectivity"</span><span class="w"> </span><span class="p">},</span>
</span><span id="__span-2-7"><a id="__codelineno-2-7" name="__codelineno-2-7" href="#__codelineno-2-7"></a><span class="w"> </span><span class="nt">"retryable"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span>
</span><span id="__span-2-8"><a id="__codelineno-2-8" name="__codelineno-2-8" href="#__codelineno-2-8"></a><span class="p">}</span>
</span></code></pre></div>
</div>
<h2 id="error-code-catalogue">Error code catalogue<a class="headerlink" href="#error-code-catalogue" title="Permanent link">&para;</a></h2>
<p>Every code below is a member of the <code>APIErrorCode</code> enumeration. The <strong>Status</strong> column
is the default HTTP status the server returns for that code. A handler can override
the status in special cases, but the defaults hold for the overwhelming majority of responses.</p>
<p>The server never answers with a <code>5xx</code> status. A proxy such as Cloudflare can replace the
body of a <code>5xx</code> with its own page, and the JSON error is then lost. Server-side failures
use <code>422</code>, and the ones that a retry can fix use <code>424</code>. Read <code>error_code</code> to tell them apart.
A <code>5xx</code> that a client receives comes from a proxy in front of the server, for example
while the server restarts.</p>
<h3 id="client-errors-4xx">Client errors (4xx)<a class="headerlink" href="#client-errors-4xx" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Code</th>
<th>Status</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>INVALID_INPUT</code></td>
<td>400</td>
<td>A required field is missing, or the request body could not be parsed. Also used as the generic "your input was malformed" code.</td>
</tr>
<tr>
<td><code>INVALID_SERVICE</code></td>
<td>400</td>
<td>The named service is unknown, or is not permitted for your API key.</td>
</tr>
<tr>
<td><code>INVALID_PROXY</code></td>
<td>400</td>
<td>The supplied proxy specification could not be resolved or is malformed, or the proxy failed the <a href="../../../guide/proxies-and-vpn/#exit-check">exit check</a>.</td>
</tr>
<tr>
<td><code>INVALID_PARAMETERS</code></td>
<td>400</td>
<td>One or more download or query parameters failed validation (bad codec, bitrate, sort field, and so on).</td>
</tr>
<tr>
<td><code>AUTH_FAILED</code></td>
<td>401</td>
<td>Authentication with the streaming service failed (bad credentials or cookies).</td>
</tr>
<tr>
<td><code>FORBIDDEN</code></td>
<td>403</td>
<td>The action is not allowed. Raised by server-side gates (per-key restrictions on CDM or credential overrides) and by remote session IP binding.</td>
</tr>
<tr>
<td><code>SERVER_CDM_CAPPED</code></td>
<td>403</td>
<td>The server CDM does not license live above the <code>server_cdm_max_height</code> of the API key. <code>details.reason</code> is <code>server_cdm_max_height</code> (with <code>details.max_height</code>), <code>client_device</code>, for a remote session where the client's own device licenses, or <code>server_device</code>, for a remote session that runs on the server's device. A remote client licenses the track with its own device, except for <code>server_device</code>: then only its own vaults can supply the key.</td>
</tr>
<tr>
<td><code>GEOFENCE</code></td>
<td>403</td>
<td>The title is not available in the applicable region.</td>
</tr>
<tr>
<td><code>NOT_FOUND</code></td>
<td>404</td>
<td>A requested resource (title, history entry, and so on) does not exist.</td>
</tr>
<tr>
<td><code>NO_CONTENT</code></td>
<td>404</td>
<td>The request was valid but produced nothing: no matching titles, tracks, episodes, or keys.</td>
</tr>
<tr>
<td><code>JOB_NOT_FOUND</code></td>
<td>404</td>
<td>The referenced download job does not exist.</td>
</tr>
<tr>
<td><code>SESSION_NOT_FOUND</code></td>
<td>404</td>
<td>The remote-dl session does not exist or has expired.</td>
</tr>
<tr>
<td><code>TRACK_NOT_FOUND</code></td>
<td>404</td>
<td>A referenced track ID is not present in the remote session.</td>
</tr>
<tr>
<td><code>CONFLICT</code></td>
<td>409</td>
<td>The target resource is in a state that disallows the action (retrying a running job, prioritising a non-queued job, clearing cache during an active download).</td>
</tr>
<tr>
<td><code>SERVER_DRAINING</code></td>
<td>409</td>
<td>The server is about to restart and starts no new remote session or download job. Open work continues. Retryable after the restart. A <code>dl --remote</code> client waits for the restart and opens a new remote session.</td>
</tr>
<tr>
<td><code>SERVICE_ERROR</code></td>
<td>422</td>
<td>The streaming service's API returned an error, or the service does not support the requested operation, or the service code exited (<code>sys.exit</code>).</td>
</tr>
<tr>
<td><code>DRM_ERROR</code></td>
<td>422</td>
<td>DRM or license acquisition failed.</td>
</tr>
<tr>
<td><code>RATE_LIMITED</code></td>
<td>429</td>
<td>The streaming service is rate-limiting requests. Retryable.</td>
</tr>
</tbody>
</table>
<div class="admonition warning">
<p class="admonition-title">Not every <code>429</code> is <code>RATE_LIMITED</code></p>
<p>The server has a rate limit of its own. An API key over <code>serve.tiers.&lt;name&gt;.rate_limit</code>
or <code>serve.users.&lt;key&gt;.rate_limit</code> gets a <code>429</code> from the authentication middleware, before
any handler runs, so it carries no <code>error_code</code> and is not the <code>RATE_LIMITED</code> code above.
It is the shape <code>{"status": 429, "message": "Rate limit exceeded."}</code> with a <code>Retry-After</code>
header. Read <code>Retry-After</code> and wait it out rather than retrying on a backoff of your own:
the window is fixed, so an early retry only spends the next window. See
<a href="../authentication/#rate-limit-rejections">Authentication</a>.</p>
</div>
<h3 id="server-errors-422-and-424">Server errors (422 and 424)<a class="headerlink" href="#server-errors-422-and-424" title="Permanent link">&para;</a></h3>
<table>
<thead>
<tr>
<th>Code</th>
<th>Status</th>
<th>Meaning</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>INTERNAL_ERROR</code></td>
<td>422</td>
<td>An unexpected server-side error. This is the fallback for any exception the server could not categorise, and for an exception that no handler caught.</td>
</tr>
<tr>
<td><code>DOWNLOAD_ERROR</code></td>
<td>422</td>
<td>The download process itself failed.</td>
</tr>
<tr>
<td><code>WORKER_ERROR</code></td>
<td>422</td>
<td>The download worker subprocess errored out.</td>
</tr>
<tr>
<td><code>NETWORK_ERROR</code></td>
<td>424</td>
<td>A network connectivity problem (connection, timeout, DNS, TLS). Retryable.</td>
</tr>
<tr>
<td><code>SERVICE_UNAVAILABLE</code></td>
<td>424</td>
<td>The service is temporarily unavailable or under maintenance. Retryable.</td>
</tr>
</tbody>
</table>
<div class="admonition note">
<p class="admonition-title">Fallback status</p>
<p>If a code is ever emitted without a mapped status, the server falls back to
<code>422</code>. In practice every code above has an explicit mapping. A middleware
in every server mode also changes any <code>5xx</code> answer, such as one from a CDM subapplication, to <code>422</code>.</p>
</div>
<h2 id="how-the-server-produces-errors">How the server produces errors<a class="headerlink" href="#how-the-server-produces-errors" title="Permanent link">&para;</a></h2>
<p>Understanding where an error comes from helps interpret it.</p>
<p><strong>Explicitly raised errors.</strong> Most endpoints raise a structured <code>APIError</code> directly.
For example, a missing <code>service</code> field yields <code>INVALID_INPUT</code>, and a disallowed
service yields <code>INVALID_SERVICE</code>. These carry a precise code, message, and often a
populated <code>details</code> object.</p>
<p><strong>Categorised exceptions.</strong> When an endpoint calls into a streaming service and an
uncategorised exception bubbles up, the server runs it through a classifier that
inspects the exception type and message and maps it to the most appropriate code.
The classification is keyword-based, checked in order:</p>
<table>
<thead>
<tr>
<th>If the error mentions...</th>
<th>It becomes</th>
<th>Retryable</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>auth</code>, <code>login</code>, <code>credential</code>, <code>unauthorized</code>, <code>forbidden</code>, <code>token</code></td>
<td><code>AUTH_FAILED</code> (401)</td>
<td>no</td>
</tr>
<tr>
<td><code>connection</code>, <code>timeout</code>, <code>network</code>, <code>unreachable</code>, <code>socket</code>, <code>dns</code>, <code>resolve</code> (or <code>ConnectionError</code>, <code>TimeoutError</code>, <code>URLError</code>, <code>SSLError</code>)</td>
<td><code>NETWORK_ERROR</code> (424)</td>
<td>yes</td>
</tr>
<tr>
<td><code>geofence</code>, <code>geoblock</code>, <code>region</code>, <code>not available in</code>, <code>territory</code></td>
<td><code>GEOFENCE</code> (403)</td>
<td>no</td>
</tr>
<tr>
<td><code>not found</code>, <code>404</code>, <code>does not exist</code>, <code>invalid id</code></td>
<td><code>NOT_FOUND</code> (404)</td>
<td>no</td>
</tr>
<tr>
<td><code>rate limit</code>, <code>too many requests</code>, <code>429</code>, <code>throttle</code></td>
<td><code>RATE_LIMITED</code> (429)</td>
<td>yes</td>
</tr>
<tr>
<td><code>drm</code>, <code>license</code>, <code>widevine</code>, <code>playready</code>, <code>decrypt</code></td>
<td><code>DRM_ERROR</code> (422)</td>
<td>no</td>
</tr>
<tr>
<td><code>service unavailable</code>, <code>503</code>, <code>maintenance</code>, <code>temporarily unavailable</code></td>
<td><code>SERVICE_UNAVAILABLE</code> (424)</td>
<td>yes</td>
</tr>
<tr>
<td><code>invalid</code>, <code>malformed</code>, <code>validation</code> (or <code>ValueError</code>, <code>ValidationError</code>)</td>
<td><code>INVALID_INPUT</code> (400)</td>
<td>no</td>
</tr>
<tr>
<td>anything else</td>
<td><code>INTERNAL_ERROR</code> (422)</td>
<td>no</td>
</tr>
</tbody>
</table>
<p>Categorised errors include a <code>reason</code> tag inside <code>details</code> (such as
<code>"network_connectivity"</code> or <code>"drm_failure"</code>) so a client can react without parsing
the message text.</p>
<p><strong>Invalid JSON bodies.</strong> If a <code>POST</code> endpoint receives a body that is not valid JSON,
the server returns <code>INVALID_INPUT</code> (400) with the parse error in
<code>details.error</code>:</p>
<div class="language-json highlight"><span class="filename">Malformed request body</span><pre><span></span><code><span id="__span-3-1"><a id="__codelineno-3-1" name="__codelineno-3-1" href="#__codelineno-3-1"></a><span class="p">{</span>
</span><span id="__span-3-2"><a id="__codelineno-3-2" name="__codelineno-3-2" href="#__codelineno-3-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"error"</span><span class="p">,</span>
</span><span id="__span-3-3"><a id="__codelineno-3-3" name="__codelineno-3-3" href="#__codelineno-3-3"></a><span class="w"> </span><span class="nt">"error_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"INVALID_INPUT"</span><span class="p">,</span>
</span><span id="__span-3-4"><a id="__codelineno-3-4" name="__codelineno-3-4" href="#__codelineno-3-4"></a><span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Invalid JSON request body"</span><span class="p">,</span>
</span><span id="__span-3-5"><a id="__codelineno-3-5" name="__codelineno-3-5" href="#__codelineno-3-5"></a><span class="w"> </span><span class="nt">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-07-03T12:00:00+00:00"</span><span class="p">,</span>
</span><span id="__span-3-6"><a id="__codelineno-3-6" name="__codelineno-3-6" href="#__codelineno-3-6"></a><span class="w"> </span><span class="nt">"details"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nt">"error"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Expecting value: line 1 column 1 (char 0)"</span><span class="w"> </span><span class="p">}</span>
</span><span id="__span-3-7"><a id="__codelineno-3-7" name="__codelineno-3-7" href="#__codelineno-3-7"></a><span class="p">}</span>
</span></code></pre></div>
<h2 id="the-authentication-error-exception">The authentication error exception<a class="headerlink" href="#the-authentication-error-exception" title="Permanent link">&para;</a></h2>
<p>There is one place where the response does <strong>not</strong> follow the standard shape: the
API key authentication middleware. When you send a request to a protected endpoint
without a valid <code>X-Secret-Key</code> header, the middleware short-circuits with a legacy
body that uses an integer <code>status</code> and no <code>error_code</code> or <code>timestamp</code>.</p>
<div class="tabbed-set tabbed-alternate" data-tabs="1:2"><input checked="checked" id="__tabbed_1_1" name="__tabbed_1" type="radio" /><input id="__tabbed_1_2" name="__tabbed_1" type="radio" /><div class="tabbed-labels"><label for="__tabbed_1_1">Missing key</label><label for="__tabbed_1_2">Invalid key</label></div>
<div class="tabbed-content">
<div class="tabbed-block">
<div class="language-json highlight"><pre><span></span><code><span id="__span-4-1"><a id="__codelineno-4-1" name="__codelineno-4-1" href="#__codelineno-4-1"></a><span class="p">{</span><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">401</span><span class="p">,</span><span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Secret Key is Empty."</span><span class="w"> </span><span class="p">}</span>
</span></code></pre></div>
</div>
<div class="tabbed-block">
<div class="language-json highlight"><pre><span></span><code><span id="__span-5-1"><a id="__codelineno-5-1" name="__codelineno-5-1" href="#__codelineno-5-1"></a><span class="p">{</span><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="mi">401</span><span class="p">,</span><span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Secret Key is Invalid."</span><span class="w"> </span><span class="p">}</span>
</span></code></pre></div>
</div>
</div>
</div>
<div class="admonition warning">
<p class="admonition-title">Handle both shapes</p>
<p>A client must expect two error formats: the standard structured error
(string <code>status</code> of <code>"error"</code>, with <code>error_code</code>), and this authentication error
(integer <code>status</code>, no <code>error_code</code>).</p>
</div>
<h2 id="late-failures-with-status-200">Late failures with status <code>200</code><a class="headerlink" href="#late-failures-with-status-200" title="Permanent link">&para;</a></h2>
<p>The remote session <code>titles</code>, <code>tracks</code> and <code>license</code> routes send status <code>200</code> and the headers
when the work takes longer than 30 seconds. They then send a newline every 30 seconds to keep
the connection open. See <a href="../endpoints/#slow-responses">Slow responses</a>. A failure after that
time arrives as the standard error body, but with status <code>200</code>. The body has no field for the
HTTP status that the error would otherwise have. <code>error_code</code> and <code>retryable</code> stay in the body.</p>
<div class="admonition warning">
<p class="admonition-title">Check the body on these routes</p>
<p>On these routes a <code>200</code> does not always mean success. Parse the body and treat
<code>"status": "error"</code> with an <code>error_code</code> as a failure.</p>
</div>
<h2 id="responses-with-no-body">Responses with no body<a class="headerlink" href="#responses-with-no-body" title="Permanent link">&para;</a></h2>
<p>Not every failure or completion has a JSON body. Some endpoints answer with
<strong><code>204 No Content</code></strong> and an empty body, notably deleting a terminal download job and
deleting a history entry.</p>
<div class="admonition warning">
<p class="admonition-title">Do not parse <code>204</code> bodies</p>
<p>A <code>204</code> response has no body. Clients must examine the status code before they
decode JSON, or the decode will fail on an empty string.</p>
</div>
<h2 id="debug-information">Debug information<a class="headerlink" href="#debug-information" title="Permanent link">&para;</a></h2>
<p>By default, error responses never include tracebacks or internal diagnostics. If you
start the server with the <code>--debug-api</code> flag, every structured error gains a
<code>debug_info</code> object:</p>
<div class="language-json highlight"><span class="filename">Error with --debug-api enabled</span><pre><span></span><code><span id="__span-6-1"><a id="__codelineno-6-1" name="__codelineno-6-1" href="#__codelineno-6-1"></a><span class="p">{</span>
</span><span id="__span-6-2"><a id="__codelineno-6-2" name="__codelineno-6-2" href="#__codelineno-6-2"></a><span class="w"> </span><span class="nt">"status"</span><span class="p">:</span><span class="w"> </span><span class="s2">"error"</span><span class="p">,</span>
</span><span id="__span-6-3"><a id="__codelineno-6-3" name="__codelineno-6-3" href="#__codelineno-6-3"></a><span class="w"> </span><span class="nt">"error_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"INTERNAL_ERROR"</span><span class="p">,</span>
</span><span id="__span-6-4"><a id="__codelineno-6-4" name="__codelineno-6-4" href="#__codelineno-6-4"></a><span class="w"> </span><span class="nt">"message"</span><span class="p">:</span><span class="w"> </span><span class="s2">"An unexpected error occurred: ..."</span><span class="p">,</span>
</span><span id="__span-6-5"><a id="__codelineno-6-5" name="__codelineno-6-5" href="#__codelineno-6-5"></a><span class="w"> </span><span class="nt">"timestamp"</span><span class="p">:</span><span class="w"> </span><span class="s2">"2026-07-03T12:00:00+00:00"</span><span class="p">,</span>
</span><span id="__span-6-6"><a id="__codelineno-6-6" name="__codelineno-6-6" href="#__codelineno-6-6"></a><span class="w"> </span><span class="nt">"debug_info"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
</span><span id="__span-6-7"><a id="__codelineno-6-7" name="__codelineno-6-7" href="#__codelineno-6-7"></a><span class="w"> </span><span class="nt">"exception_type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"KeyError"</span><span class="p">,</span>
</span><span id="__span-6-8"><a id="__codelineno-6-8" name="__codelineno-6-8" href="#__codelineno-6-8"></a><span class="w"> </span><span class="nt">"traceback"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Traceback (most recent call last): ..."</span>
</span><span id="__span-6-9"><a id="__codelineno-6-9" name="__codelineno-6-9" href="#__codelineno-6-9"></a><span class="w"> </span><span class="p">}</span>
</span><span id="__span-6-10"><a id="__codelineno-6-10" name="__codelineno-6-10" href="#__codelineno-6-10"></a><span class="p">}</span>
</span></code></pre></div>
<p>The <code>debug_info</code> object always carries <code>exception_type</code> and, for exception-derived
errors, a formatted <code>traceback</code>. Some endpoints add extra diagnostics such as
captured job worker stderr.</p>
<div class="admonition warning">
<p class="admonition-title">Developer use only</p>
<p><code>--debug-api</code> exposes internal tracebacks in responses. Enable it only for local
debugging, never on a server reachable by untrusted clients.</p>
</div>
<h2 id="client-handling-recommendations">Client handling recommendations<a class="headerlink" href="#client-handling-recommendations" title="Permanent link">&para;</a></h2>
<p>For anyone writing a consumer of the API, a durable strategy is:</p>
<ol>
<li><strong>Read the HTTP status first.</strong> It tells you the broad class of outcome, and it
lets you find the <code>204</code>/no-body and authentication-error cases before you read the
body.</li>
<li><strong>Branch on <code>error_code</code>.</strong> For structured errors, this is the stable identifier
to switch on. Do not use <code>message</code> as the identifier.</li>
<li><strong>Respect <code>retryable</code>.</strong> When it is <code>true</code>, back off and try the request again.
When absent, fix the request rather than repeating it.</li>
<li><strong>Fall back gracefully.</strong> For an unrecognised code, show the <code>message</code> and the
HTTP status.</li>
</ol>
<div class="admonition note">
<p class="admonition-title">Reference consumer</p>
<p>unshackle's own remote-download client treats any status of <code>400</code> or above as
fatal, and a <code>200</code> body with <code>"status": "error"</code> and an <code>error_code</code> too: it logs
<code>Server error [&lt;error_code&gt;]: &lt;message&gt;</code> and exits. It retries a request once,
after one second, only when a <code>502</code>, <code>503</code> or <code>504</code> arrives with a body that is
not JSON: that is a page from the proxy in front of the server, not an answer
from the server. This is a reasonable template for your own client's error
handling.</p>
</div>
</article>
</div>
<script>var tabs=__md_get("__tabs");if(Array.isArray(tabs))e:for(var set of document.querySelectorAll(".tabbed-set")){var labels=set.querySelector(".tabbed-labels");for(var tab of tabs)for(var label of labels.getElementsByTagName("label"))if(label.innerText.trim()===tab){var input=document.getElementById(label.htmlFor);input.checked=!0;continue e}}</script>
<script>var target=document.getElementById(location.hash.slice(1));target&&target.name&&(target.checked=target.name.startsWith("__tabbed_"))</script>
</div>
<button type="button" class="md-top md-icon" data-md-component="top" hidden>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M13 20h-2V8l-5.5 5.5-1.42-1.42L12 4.16l7.92 7.92-1.42 1.42L13 8z"/></svg>
Back to top
</button>
</main>
<footer class="md-footer">
<nav class="md-footer__inner md-grid" aria-label="Footer" >
<a href="../remote-sessions/" class="md-footer__link md-footer__link--prev" aria-label="Previous: Remote Sessions">
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11z"/></svg>
</div>
<div class="md-footer__title">
<span class="md-footer__direction">
Previous
</span>
<div class="md-ellipsis">
Remote Sessions
</div>
</div>
</a>
<a href="../../../reference/api/service/" class="md-footer__link md-footer__link--next" aria-label="Next: Service">
<div class="md-footer__title">
<span class="md-footer__direction">
Next
</span>
<div class="md-ellipsis">
Service
</div>
</div>
<div class="md-footer__button md-icon">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11z"/></svg>
</div>
</a>
</nav>
<div class="md-footer-meta md-typeset">
<div class="md-footer-meta__inner md-grid">
<div class="md-copyright">
Made with
<a href="https://squidfunk.github.io/mkdocs-material/" target="_blank" rel="noopener">
Material for MkDocs
</a>
</div>
</div>
</div>
</footer>
</div>
<div class="md-dialog" data-md-component="dialog">
<div class="md-dialog__inner md-typeset"></div>
</div>
<script id="__config" type="application/json">{"annotate": null, "base": "../../..", "features": ["content.code.annotate", "content.code.copy", "content.tabs.link", "content.tooltips", "navigation.footer", "navigation.indexes", "navigation.sections", "navigation.tabs", "navigation.top", "navigation.tracking", "search.highlight", "search.share", "search.suggest", "toc.follow"], "search": "../../../assets/javascripts/workers/search.a7633da7.min.js", "tags": null, "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}, "version": null}</script>
<script src="../../../assets/javascripts/bundle.c21346df.min.js"></script>
</body>
</html>