Skip to content

Why C-MOVE is strange when you come from HTTP

Tonight · ~15 min · read · energy: low · setup: none

Of all the DIMSE verbs, C-MOVE is the one that breaks a web engineer’s brain. This short lesson isolates exactly why, because “I queried but nothing arrived” is one of the most common PACS-integration confusions — and it is purely a mental-model problem, not a bug.

The anchor: C-MOVE is a three-party operation

In HTTP, a retrieve is two-party: you ask, the server answers, on the same connection. C-MOVE is three-party. You (the SCU) tell a source SCP: “send these objects to that AE over there.” The source SCP then opens a new, separate association to the destination AE and C-STOREs the objects to it.

sequenceDiagram
    participant W as Workstation (SCU)
    participant P as PACS (SCP)
    participant D as Destination AE (SCP)
    W->>P: C-FIND (query keys)
    P-->>W: matching identifiers
    W->>P: C-MOVE (match, destination=D)
    P-->>W: status: pending / success
    P->>D: new association: C-STORE the images
    D-->>P: C-STORE responses

Notice: the images flow on the P → D arrow, not on the W ↔ P arrows. The workstation that asked for them is not necessarily their destination.

Why it was designed this way

C-MOVE lets a thin client ask a PACS to push a study directly to a thick viewer or another archive, without the client having to receive and re-forward gigabytes of pixels. The “move” is a server-to-server push initiated by a lightweight request. That is elegant for its 1990s purpose and deeply counterintuitive if you learned networking from the web.

What the response status actually means (the part to get right)

The Move SCP sends a final response only after all the C-STORE sub-operations to the destination have finished (it may send optional Pending responses meanwhile). That final status is precise, and it is the part HTTP intuition gets wrong. Per DICOM PS3.4 (Table C.4-2, VERIFIED):

Status Code Meaning
Success 0000 Sub-operations Complete — No Failures. Every C-STORE to the named destination succeeded (NumberOfFailedSuboperations = 0).
Warning B000 Sub-operations Complete — One or more Failures. Some C-STOREs failed (NumberOfFailedSuboperations > 0).
Failure A801 Refused: Move Destination unknown — the SCP does not recognise the destination AE; no C-STOREs are attempted.
Failure A701/A702 Refused: out of resources.
Failure Cxxx Failed: unable to process.

Two consequences that correct the web-engineer intuition:

  • Unknown destination is a failure, not a silent success. If the PACS does not know the Move Destination AE Title → host/port mapping, it returns A801 (Failure) and attempts no C-STOREs. The error is not silent — but the bare hex code is opaque to a beginner, which is why it feels mysterious.
  • A destination/connectivity/storage failure is never a 0000 Success. Where the failure sits decides the final status: if some C-STORE sub-operations ran and failed (destination not listening, behind a firewall, or rejects the objects), the response is a Warning (B000) with NumberOfFailedSuboperations > 0; if the SCP cannot perform the sub-operations at all (e.g. it cannot open the association to the destination, or is out of resources), it is a Failure such as A702 (unable to perform sub-operations) or a Cxxx (unable to process). A genuine 0000 (Success) means every C-STORE to the named destination succeeded.

So when does “success but nothing in my script” actually happen?

It is an expectation mismatch, not a protocol lie. 0000 means the images were delivered to the destination AE you named in the request. Because C-MOVE sends to a third party (not back over the asking connection), that destination is not your requesting script unless you (a) named your own AE as the destination and (b) are running a storage SCP there. If you did neither, the PACS did exactly what you asked — push to some other AE — and your script correctly received nothing. The fix is to run a storage SCP (the equivalent of storescp) at a known destination AE, or use C-GET to pull the pixels back over the same association.

C-GET is the two-party alternative (“send them back to me”), and it avoids the destination configuration — but many PACS disable C-GET for security (it lets a client pull arbitrary data), so C-MOVE remains the real-world default.

Stop and think — then reveal

You run findscu (C-FIND) and see the study, then movescu (C-MOVE) and the SCP returns status A801. No images arrive. What does A801 mean, and what were you missing?

A801 is “Refused: Move Destination unknown” — a Failure. The Move SCP does not recognise the destination AE Title you supplied (it is not in the SCP’s destination table, or the AE Title → host/port mapping is wrong), so it attempts no C-STOREs and returns failure. You were missing a correct, registered Move Destination: configure the destination AE on the PACS side, or run a storage SCP at a known AE and name that AE as the destination. Note this is not a “success into the void” — A801 is an explicit failure. The only case where images genuinely do not arrive despite a 0000 (Success) is when they were delivered to a different named destination than your requesting process.

What to retain

  1. C-MOVE is three-party: the asker tells the source to push objects to a separate destination AE; the pixels never flow back over the asking connection.
  2. The Move SCP’s final status is precise (PS3.4 Table C.4-2): 0000 Success = all C-STOREs to the named destination succeeded; B000 Warning = one or more sub-operations failed; A801 Failure = Move Destination unknown (no C-STOREs attempted). Use NumberOfCompleted/Failed/WarningSuboperations to diagnose.
  3. A destination/connectivity/storage failure is never 0000 Success: it surfaces as a B000 Warning (some sub-operations ran and failed) or a Failure such as A702/Cxxx (SCP unable to perform the sub-operations), never as Success. A801 is the specific Failure for an unknown Move Destination. A genuine 0000 means the images reached the named destination.
  4. The real “nothing in my script after Success” is an expectation mismatch: the images went to the named third-party destination, not your requesting process. Run a storage SCP at a known destination, or use C-GET (where supported).

Next: the modern, web-friendly skin over the same concepts — DICOMweb.