@@ -935,7 +935,7 @@ the following keys:
935935
936936``status ``
937937 A string with valid values ``pending ``, ``processing ``, ``complete ``, ``error ``, and ``canceled ``
938- indicating the current state of the file upload session.
938+ indicating the current :ref: ` state of the file upload session < file-upload-session-states >` .
939939
940940``expires-at ``
941941 An :rfc: `3339 ` formatted timestamp string representing when the server will expire this file upload
@@ -969,6 +969,98 @@ For the ``links`` key in the response payload, the following sub-keys are valid:
969969 <file-upload-session-extension>` (via ``POST ``). If the server does not support file upload session
970970 extensions, this key **MUST ** be omitted.
971971
972+ .. _file-upload-session-states :
973+
974+ File Upload Session States
975+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
976+
977+ A file upload session is always in exactly one of the following states, reported by the ``status `` key of the
978+ :ref: `file upload session status response <file-upload-session-response >`. The same value is reflected for the
979+ file in the ``files `` mapping of the :ref: `publishing session status <publishing-session-files >`.
980+
981+ ``pending ``
982+ The file upload session has been created and the negotiated :ref: `upload mechanism
983+ <file-upload-mechanisms>` is being executed; the file's bytes are in transit or not yet fully transferred.
984+ A newly created session starts in this state and remains in it until the client :ref: `completes
985+ <file-upload-session-completion>` or :ref: `cancels <file-upload-session-cancellation >` the upload. A file
986+ whose upload is still ``pending `` cannot be :ref: `replaced <replacing-files >`.
987+
988+ ``processing ``
989+ The client has requested completion and the server accepted the request for deferred processing, returning
990+ a ``202 Accepted `` (see :ref: `file-upload-session-completion `). This is a transitional state; the client
991+ polls the :ref: `file upload session status <file-upload-session-status >`, respecting the ``Retry-After ``
992+ header, until it resolves to ``complete `` or ``error ``.
993+
994+ ``complete ``
995+ The file has been fully uploaded, validated, and accepted into the publishing session. The file can still
996+ be :ref: `deleted <file-upload-session-cancellation >`, which removes it from the publishing session and
997+ moves this session to ``canceled ``.
998+
999+ ``error ``
1000+ The upload failed and the file is **not ** in a usable state. Unlike a :ref: `publishing session in the
1001+ error state <publishing-session-states>`, a file upload session cannot be repaired in place: the client
1002+ **MUST ** :ref: `cancel or delete <file-upload-session-cancellation >` the file and, if it still wants to
1003+ upload it, begin an entirely new file upload session. A file upload session enters ``error `` whenever a
1004+ completion attempt fails -- whether the server detects the failure synchronously within the ``complete ``
1005+ request, or asynchronously while the session is ``processing ``.
1006+
1007+ ``canceled `` (terminal)
1008+ The session was canceled (an in-progress upload) or its completed file was deleted. The session resource
1009+ and its associated upload mechanisms **MUST NOT ** be assumed reusable; recovering or replacing the file
1010+ requires a new file upload session.
1011+
1012+ Only ``canceled `` is terminal. Both ``complete `` and ``error `` still permit a ``DELETE `` (which moves the
1013+ session to ``canceled ``); from ``error ``, deletion is the only forward action.
1014+
1015+ The transitions between these states are:
1016+
1017+ .. list-table ::
1018+ :header-rows: 1
1019+
1020+ * - From
1021+ - Event
1022+ - To
1023+ * - *(none) *
1024+ - File upload session created (``202 Accepted ``)
1025+ - ``pending ``
1026+ * - ``pending ``
1027+ - Upload mechanism executes (bytes transferred)
1028+ - ``pending ``
1029+ * - ``pending ``
1030+ - Completion request completed immediately (``201 Created ``)
1031+ - ``complete ``
1032+ * - ``pending ``
1033+ - Completion request accepted for deferred processing (``202 Accepted ``)
1034+ - ``processing ``
1035+ * - ``pending ``
1036+ - Completion request fails synchronously
1037+ - ``error ``
1038+ * - ``pending ``
1039+ - Cancellation requested (``DELETE ``)
1040+ - ``canceled ``
1041+ * - ``processing ``
1042+ - Deferred processing succeeds
1043+ - ``complete ``
1044+ * - ``processing ``
1045+ - Deferred processing fails
1046+ - ``error ``
1047+ * - ``processing ``
1048+ - Cancellation requested
1049+ - rejected with ``409 Conflict `` (see :ref: `file-upload-session-cancellation `)
1050+ * - ``complete ``
1051+ - File deleted (``DELETE ``)
1052+ - ``canceled ``
1053+ * - ``error ``
1054+ - File deleted (``DELETE ``)
1055+ - ``canceled ``
1056+
1057+ Unlike a publishing session -- where a synchronous publish failure leaves the session editable and only a
1058+ *deferred * failure reaches the ``error `` state -- a file upload session treats *any * completion failure as
1059+ fatal to the file, because a partially or incorrectly uploaded file cannot be edited in place. Both a
1060+ synchronous and a deferred completion failure therefore move the session to ``error ``, from which the client
1061+ deletes the file and starts over.
1062+
1063+
9721064.. _file-upload-session-completion :
9731065
9741066Complete a File Upload Session
@@ -1002,6 +1094,11 @@ If the server responds with a ``202 Accepted``, clients may poll the file upload
10021094for the status to change. Clients **SHOULD ** respect the ``Retry-After `` header value of the file upload
10031095session status response.
10041096
1097+ If a completion attempt fails -- synchronously (in which case the server also returns an :ref: `error response
1098+ <session-errors>`) or asynchronously while the session is ``processing `` -- the session moves to the
1099+ :ref: `error state <file-upload-session-states >`, from which the client must :ref: `cancel or delete
1100+ <file-upload-session-cancellation>` the file and start a new file upload session to retry.
1101+
10051102
10061103.. _file-upload-session-cancellation :
10071104
@@ -1015,10 +1112,18 @@ to delete.
10151112
10161113A successful deletion request **MUST ** respond with a ``204 No Content ``.
10171114
1115+ A ``DELETE `` is permitted while the session is ``pending `` (canceling an in-progress upload), ``complete ``
1116+ (deleting an uploaded file), or ``error `` (discarding a failed upload). If the session is in the
1117+ ``processing `` state -- that is, a deferred completion is already underway -- the server **MUST ** reject the
1118+ ``DELETE `` with a ``409 Conflict ``, since the outcome is already being decided. The client can instead wait
1119+ for processing to resolve and then delete the file if needed.
1120+
10181121Once canceled or deleted, a client **MUST NOT ** assume that the previous file upload session resource or
10191122associated file upload mechanisms can be reused.
10201123
10211124
1125+ .. _replacing-files :
1126+
10221127Replacing a Partially or Fully Uploaded File
10231128~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
10241129
@@ -1612,6 +1717,11 @@ Change History
16121717 entering ``error ``, and require the server to reject cancellation with a ``409 Conflict `` while a session is
16131718 ``processing ``. Key the **Multiple Session Creation Requests ** rule off any non-terminal state rather than
16141719 ``pending ``.
1720+ * Document the file upload session state machine with a **File Upload Session States ** section and transition
1721+ table. Specify that any completion failure -- synchronous or deferred -- moves the session to ``error ``,
1722+ that an ``error `` file cannot be repaired in place (the client cancels or deletes it and starts a new file
1723+ upload session), and that the server **MUST ** reject a ``DELETE `` with a ``409 Conflict `` while a session
1724+ is ``processing ``.
16151725
16161726* `07-Dec-2025 <https://discuss.python.org/t/pep-694-pypi-upload-api-2-0-round-2/101483/35 >`__
16171727
0 commit comments