Troubleshooting
Common DICOM Integration Errors
38 production patterns that break DICOM integration — grouped by severity so you can scan patient-safety issues first. Each entry has a diagnosis (what's happening), a fix (concrete remediation), and a link to the affected attribute's full reference.
high High — patient-safety / data-loss risk
-
Accession Number truncation at 16 chars (SH limit)
(0008,0050)Accession NumberDiagnosis: Some EHRs (notably Epic legacy, some custom HIS) generate accession numbers >16 chars. DICOM's SH VR caps at 16 chars; the modality's Worklist SCU silently truncates, then the resulting study lands with a different (short) AccessionNumber than the order, breaking reconciliation.
Fix: Either (a) constrain the source HIS to ≤16 chars, or (b) hash the long accession (e.g., MD5 first 16 chars) and maintain a mapping table for back-lookup. Long-term: pursue the SH-cap removal in IHE RAD profiles.
-
BitsAllocated=8 on 16-bit modality output causes pixel overflow
(0028,0100)Bits AllocatedDiagnosis: Modality firmware bug: modality actually acquires 12-bit radiographic data but writes BitsAllocated=8 in the DICOM header. Storing in 8-bit truncates the dynamic range; window/level presets from the header describe values beyond the stored range.
Fix: Validate BitsAllocated against the modality's known acquisition bit depth. For CR/DX/CT, BitsAllocated should be 16. If 8 appears, reject with a validation error and alert the modality support team — usually a firmware bug.
-
ModalitiesInStudy stale after series ingestion
(0008,0061)Modalities in StudyDiagnosis: PACS is SCP for multiple modalities sending to the same study. First series arrives with ModalitiesInStudy='CT'; later PET series adds to the same study but the archived ModalitiesInStudy stays 'CT' because the initial ingestion wrote it and no re-aggregation runs. Q/R by ModalitiesInStudy=PT then misses the study entirely.
Fix: On every C-STORE, recompute ModalitiesInStudy by aggregating over all series Modality values. Most mature PACS do this; home-grown archives and thin DICOM gateways often don't.
-
Patient ID conflicts between EHR MRN and DICOM PatientID
(0010,0020)Patient IDDiagnosis: EHR is the source of truth for MRN but the modality's worklist query returned a different PatientID (e.g., the visit number). DICOM lands with the wrong PatientID and breaks patient reconciliation downstream.
Fix: Apply Mirth-side reconciliation: query the EHR (via FHIR Patient resource or HL7 v2 QBP) using the DICOM AccessionNumber, fetch the canonical MRN, and rewrite (0010,0020) before forwarding to the long-term archive.
-
PatientPosition HFS/FFS swap causes z-axis flip in 3D reconstruction
(0018,5100)Patient PositionDiagnosis: Patient scanned feet-first but technologist left modality set to default HFS. 3D MPR/MIP reconstructions render the patient inverted. Clinicians may miss pathology on the wrong side.
Fix: Cross-check PatientPosition against ImageOrientationPatient at reconstruction time. Flag studies where the two are inconsistent for review. Some viewers auto-correct silently; explicit alerts prevent downstream confusion.
-
Empty PatientName rejected by downstream PACS
(0010,0010)Patient's NameDiagnosis: Some PACS / VNA implementations mandate a non-empty (0010,0010). When the source DICOM has PatientName = '' or contains only delimiters ('^^^^'), the SCP returns Status 0xA900 (Identifier Does Not Match SOP Class) on STORE, or QIDO-RS returns 400.
Fix: Default to '^^^^^^' (5 carets for empty 5-component PN) on the perimeter channel before forwarding. Alternatively, drop the message and notify upstream — never silently insert a fake name.
-
Patient Weight in pounds when DICOM expects kg
(0010,1030)Patient's WeightDiagnosis: HIS sends weight as 165 (lb) in HL7 v2 OBX. Mirth transformer copies the value into DICOM PatientWeight without unit conversion. PET SUV calculations use 165 kg → activity per kg drops 2.2x → SUV results clinically misleading.
Fix: Always check OBX-6 (Units) before reading OBX-5 (Value). If lb: convert to kg (lb / 2.20462). Reject inconsistent weight values (<1 kg, >600 kg) entirely.
-
Pixel Data corruption from JPEG 2000 transcoding
(7FE0,0010)Pixel DataDiagnosis: Mirth or upstream gateway transcodes JPEG 2000 Lossless to Implicit VR Little Endian (uncompressed) for compatibility. Result: PixelData length doesn't match expected uncompressed bytes due to incorrect padding handling.
Fix: Use a battle-tested DICOM library (dcm4che, pixelmed) for transcoding rather than rolling your own. Validate the output by computing expected uncompressed length (Rows × Columns × Frames × BitsAllocated/8 × SamplesPerPixel) and comparing.
-
PixelData length doesn't match Rows × Columns × BitsAllocated × SamplesPerPixel / 8
(7FE0,0010)Pixel DataDiagnosis: Calculated expected pixel data size (e.g., 512 rows × 512 cols × 16 bits × 1 sample / 8 = 524,288 bytes) doesn't match actual PixelData length. Indicates frame count mismatch (multi-frame), truncation during transmission, or a padding-byte bug in the modality's encoder.
Fix: At ingress, compute the expected bulk-data size from the header fields and compare against actual PixelData length. If multi-frame, multiply by NumberOfFrames. Log deviations and route to QC rather than silently storing corrupt bytes.
-
Image dimensions don't match Pixel Data length
(0028,0010)RowsDiagnosis: (0028,0010) Rows × (0028,0011) Columns × bytes-per-pixel ≠ length of (7FE0,0010) Pixel Data. File is corrupt or partially uploaded.
Fix: Validate at perimeter: compute expected pixel data length from Rows/Columns/BitsAllocated/SamplesPerPixel and compare to actual length. On mismatch: route to quarantine, do not forward to PACS.
-
SamplesPerPixel=3 on 'grayscale' PhotometricInterpretation
(0028,0002)Samples per PixelDiagnosis: Ultrasound or secondary capture emits SamplesPerPixel=3 (color) with PhotometricInterpretation=MONOCHROME2 (grayscale). Conflicting values; viewers handle inconsistently — some render black, some crash.
Fix: Validate the SamplesPerPixel / PhotometricInterpretation combination at ingress. MONOCHROME1/2 require 1; RGB/YBR_* require 3; PALETTE COLOR requires 1 with lookup tables. Reject or quarantine inconsistent combinations.
-
Same Study Instance UID re-used by mistake
(0020,000D)Study Instance UIDDiagnosis: Modality firmware bug or operator error generates the same (0020,000D) for two different studies. Second study overwrites the first in the PACS or fails QIDO-RS lookup with ambiguous result.
Fix: Add a Mirth de-duplication filter: maintain `seen_studies` map in `globalChannelMap` keyed by StudyInstanceUID. On collision, route to a quarantine channel and notify the modality biomed team.
-
UID exceeds 64-character cap
(0020,000D)Study Instance UIDDiagnosis: DICOM UI VR caps at 64 chars. Some modalities concatenate vendor-specific suffixes that exceed the cap. PACS rejects with Status 0xC000.
Fix: Validate UID length before forward in your DICOM Reader transformer: `if (uid.length > 64) { reject }`. Notify modality vendor — UID generators must respect the cap.
-
TransferSyntaxUID declared but not honored
(0002,0010)Transfer Syntax UIDDiagnosis: File's FMI header declares Transfer Syntax UID 1.2.840.10008.1.2.4.90 (JPEG 2000 Lossless) but the pixel data is actually uncompressed little-endian. Happens when modality's DICOM library header-writing and pixel-writing paths aren't synchronized. Viewers attempting JPEG 2000 decode fail; viewers guessing encoding may succeed.
Fix: On ingress, verify the declared transfer syntax matches the actual pixel data encoding. For JPEG-family, confirm the JPEG magic bytes at the start of each frame. If mismatch: reject and alert the sender. Do NOT attempt to auto-detect and rewrite — that's a compliance violation.
medium Medium — workflow disruption
-
Accession Number used inconsistently across systems
(0008,0050)Accession NumberDiagnosis: Order entry uses ORC-2 (Placer Order Number) for a unique identifier, but the modality's AccessionNumber comes from OBR-18 (Placer Field 1) populated with a different value. DICOM's AccessionNumber doesn't match HIS's order.
Fix: Per IHE RAD-TF Vol 2, AccessionNumber should be OBR-18. Audit your worklist SCP's mapping. Some sites use a Z-segment (ZDS-1) — confirm with your conformance statement.
-
BodyPartExamined non-standard values break routing
(0018,0015)Body Part ExaminedDiagnosis: PS3.16 Table L defines standard BodyPartExamined values (CHEST, ABDOMEN, BRAIN, etc.) but modalities emit variants ('HEAD' vs 'BRAIN', 'ABD' vs 'ABDOMEN', 'C-SPINE' vs 'CSPINE'). Routing rules that match on the defined term alone miss cases.
Fix: Normalize BodyPartExamined at perimeter with a synonym map. Compare against PS3.16 Table L on ingress; log deviations so the site can backfill the synonym map over time.
-
Frame of Reference UID changes mid-study — registration broken
(0020,0052)Frame of Reference UIDDiagnosis: Series within a single study have different FrameOfReferenceUID. Cross-series registration (e.g., MR to CT for radiation therapy) fails because the coordinate systems aren't declared linked.
Fix: On perimeter: compute FrameOfReferenceUID histogram per study. If multiple FORs in one study, route to RT planning team for explicit registration step. Don't blindly assume linkage.
-
Image Position (Patient) jumps mid-series indicate patient repositioning
(0020,0032)Image Position (Patient)Diagnosis: MR / CT series shows a slice gap >50mm in z-direction mid-series. Patient was repositioned by tech mid-acquisition. Some 3D reconstruction software fails silently; volumetric measurements are wrong.
Fix: Alert on perimeter: track previous instance's z-position; if delta > expected slice thickness × 5, log warning and route to QC for review. Notify acquisition tech via email/Slack alert.
-
Empty second component of ImageType breaks DERIVED/ORIGINAL routing
(0008,0008)Image TypeDiagnosis: Modality emits ImageType='ORIGINAL\\' (second component empty) when PS3.3 requires it to be PRIMARY or SECONDARY. Downstream routers that branch on ImageType[1] get undefined and default to main archive, even for secondary captures.
Fix: Validate ImageType at ingress: if length < 2 or values[1] empty, reject with explicit error rather than defaulting. Vendors sometimes patch this silently in firmware updates — test after any modality firmware upgrade.
-
Modality 'OT' (Other) instead of expected code
(0008,0060)ModalityDiagnosis: Legacy modality emits Modality='OT' for everything. Downstream routing channels can't distinguish CT from MR from US.
Fix: Fall back to (0008,0016) SOP Class UID lookup — derive the modality from the Storage SOP Class. Maintain a SOP Class → Modality map in the channel's configurationMap.
-
Modality mismatch between SOP Class and (0008,0060) tag
(0008,0060)ModalityDiagnosis: DICOM file has SOP Class = CT Image Storage but Modality = 'MR'. Often caused by a faulty modality conversion or operator override at the modality console.
Fix: QC check: in Mirth, fail-fast when the SOP Class's expected modality doesn't match (0008,0060). Route to quarantine + notify radiology IT.
-
Leading-zero stripping breaks lookups
(0010,0020)Patient IDDiagnosis: PatientID '00012345' arrives correctly but the Mirth transformer reads it as integer (12345) and emits the integer form downstream. EHR lookups on '12345' fail to match the canonical zero-padded MRN.
Fix: Always read PatientID as String — never `parseInt`. In Mirth: `String(msg.dataset.attr.(@tag == '00100020').value)` not `parseInt(...)`.
-
Patient Age (AS) computed from wrong reference date
(0010,1010)Patient's AgeDiagnosis: Modality computes PatientAge at acquisition time using wall-clock, but the patient's recorded BirthDate has a year typo (e.g., 1099 instead of 1999). PatientAge appears as '925Y' which downstream age-based protocols then reject or treat as adult.
Fix: Validate computed age plausibility on perimeter: 0 ≤ years ≤ 120. On out-of-range, recompute from PatientBirthDate (0010,0030); if BirthDate is also implausible, flag for biomed/EHR review.
-
Multi-byte character encoding mismatch garbles non-ASCII names
(0010,0010)Patient's NameDiagnosis: Modality emits PatientName in ISO-IR 100 (Latin-1) but receiver expects UTF-8 (ISO-IR 192). The (0008,0005) Specific Character Set tag is set incorrectly or absent. Names with é, ü, ñ, or CJK characters render as mojibake (e.g., 'José' instead of 'José').
Fix: Set (0008,0005) = 'ISO_IR 192' and re-encode the name as UTF-8 in your transformer. Mirth's `new java.lang.String(bytes, 'ISO-8859-1')` then `.getBytes('UTF-8')` is the canonical conversion.
-
MPPS N-CREATE arrives without N-SET completion
(0040,0244)Performed Procedure Step Start DateDiagnosis: Modality sends N-CREATE for performed procedure step but never sends the corresponding N-SET when the procedure completes (often due to mid-procedure cancellation or modality crash). RIS shows perpetually 'In Progress' studies.
Fix: Scheduled batch job: any MPPS open >24h gets a synthetic 'DISCONTINUED' N-SET injected so RIS state can settle. Mirth Database Reader pattern + custom Z-segment to flag the synthetic completion for audit.
-
YBR_FULL_422 from legacy ultrasound renders wrong on modern viewers
(0028,0004)Photometric InterpretationDiagnosis: Legacy ultrasounds emit YBR_FULL_422 color-space images. Older viewers handled this correctly; modern DICOM libraries (dicomParser, cornerstone.js) don't always have YBR_FULL_422 decoders and render the color channels swapped or shifted.
Fix: On ingress, detect YBR_FULL_422 and transcode to RGB at the Mirth channel. Losless transcoding is trivial with DCMTK's dcmconv. Saves downstream debugging.
-
Pixel Spacing reversed (col,row vs row,col)
(0028,0030)Pixel SpacingDiagnosis: DICOM PS3.3 mandates row-spacing first, column-spacing second. Some legacy modalities reverse the order, causing measurements in viewers to be off by the spacing ratio.
Fix: Cross-check with (0028,0011) Columns vs (0028,0010) Rows — for non-square pixels, Pixel Spacing values should track. If suspiciously reversed: contact modality vendor for firmware patch; in the interim, swap on perimeter.
-
Priority code value drift between v2.4 and v2.5+
(0040,1003)Requested Procedure PriorityDiagnosis: HL7 v2.4 uses OBR-27.6 for priority; v2.5+ moved it to TQ1-9. Mirth channel reads OBR-27.6 only; v2.5+ source omits it; DICOM RequestedProcedurePriority defaults to 'ROUTINE' when message was actually 'STAT'.
Fix: Read TQ1-9 first, fall back to OBR-27.6: `var prio = msg['TQ1'][9][1] || msg['OBR'][27][6];`. Test against both v2.4 and v2.5+ source samples.
-
Series InstanceUID re-used across modalities
(0020,000E)Series Instance UIDDiagnosis: Modality firmware regression generates SeriesInstanceUIDs that aren't actually unique — same UID emitted for different series within a study or across studies. PACS series count drops; downstream viewers show incorrect series organization.
Fix: Run a daily integrity check: `SELECT series_uid, COUNT(*) FROM instances GROUP BY series_uid HAVING COUNT(*) > N` (where N is your typical max instances per series). Alert when above threshold. Push the modality vendor for a firmware patch.
-
Specific Character Set absent — receiver assumes ISO-IR 6 (ASCII)
(0008,0005)Specific Character SetDiagnosis: Per DICOM PS3.5, (0008,0005) is Type 1C — required when text fields contain non-ASCII characters. Modality omits the tag but emits Latin-1 bytes in PatientName. Receiver displays mojibake.
Fix: On perimeter, if (0008,0005) is absent and any text field has bytes >0x7F: insert (0008,0005) = 'ISO_IR 100' (Latin-1) by default and log a warning. Push modality vendor for compliance.
-
UTF-8 data written without SpecificCharacterSet=ISO_IR 192
(0008,0005)Specific Character SetDiagnosis: Modality acquires a name with non-ASCII characters (e.g., 'Müller', 'García') but doesn't set (0008,0005) SpecificCharacterSet. Default is ISO_IR 6 (ASCII). Downstream parsers interpret the UTF-8 bytes as ASCII and see mojibake ('Müller').
Fix: At ingress, scan text-typed attributes (PN, LO, SH, LT, UT, ST) for non-ASCII bytes. If found and SpecificCharacterSet is missing or ASCII, set SpecificCharacterSet to 'ISO_IR 192' (UTF-8) explicitly. Most modern systems default to UTF-8 but some legacy archives require the tag be set.
-
Structured Report ValueType encoded inconsistently across vendors
(0040,A040)Value TypeDiagnosis: DICOM SR requires (0040,A040) ValueType as one of CODE, TEXT, NUM, PNAME, UIDREF, DATETIME, DATE, TIME, CONTAINER, IMAGE, COMPOSITE, SCOORD, SCOORD3D, TCOORD, WAVEFORM. Some vendors emit lowercase, extra whitespace, or non-standard types like 'STRING' — downstream SR parsers reject.
Fix: Validate ValueType against the defined-term enum at ingress. Uppercase + trim whitespace. Reject non-defined terms with explicit error; common deviations (e.g., 'STRING' → 'TEXT') can be rewritten by policy if the site accepts the risk.
-
Multi-value WindowCenter parsed as single value
(0028,1050)Window CenterDiagnosis: Modality emits multi-valued WindowCenter '40\\400\\-50' for brain/bone/lung presets. Viewer or Mirth transformer naively calls parseFloat() on the whole string, gets NaN, falls back to default window center (0) — images display as nearly-black or saturated.
Fix: Always split WindowCenter / WindowWidth on backslash before parseFloat. Read both into arrays and pick the first preset for default rendering. Use subsequent presets to populate preset buttons in custom viewers.
low Low — cosmetic / minor
-
Manufacturer name varies across same vendor's modalities
(0008,0070)ManufacturerDiagnosis: Same vendor's CT and MR scanners report Manufacturer differently — 'GE MEDICAL SYSTEMS' vs 'G.E. Medical Systems' vs 'GE'. Vendor-specific quirk handlers don't fire when matching is exact-string.
Fix: Normalize to a canonical form on perimeter: uppercase, strip non-alpha, prefix-match on known vendor stems. Mirth lookup: `if (mfr.toUpperCase().indexOf('GE') === 0) vendor = 'GE'`.
-
Manufacturer spelling variations break vendor-specific workflows
(0008,0070)ManufacturerDiagnosis: Sites that need vendor-specific handling (e.g., GE vs Siemens CT reconstruction kernels) match on (0008,0070) Manufacturer. Different modalities from the same vendor can emit 'GE MEDICAL SYSTEMS', 'GE Medical Systems', 'GE', 'General Electric' across firmware versions. Regex-based routing misses some.
Fix: Normalize manufacturer at ingress with a vendor alias map (JSON lookup of canonical names keyed by common variants). Refresh map when new modality models are acquired.
-
Patient Sex non-standard codes from legacy modalities
(0010,0040)Patient's SexDiagnosis: Older modalities emit non-standard sex codes ('1', '2', 'MALE', 'FEMALE'). DICOM CS expects M/F/O/U; downstream EHRs reject anything else.
Fix: Normalize on perimeter. Mirth lookup table: `{'M':'M','F':'F','O':'O','U':'U','1':'M','2':'F','MALE':'M','FEMALE':'F'}`. Default to 'U' on unknown.
-
Referring Physician name format inconsistency between RIS and modality
(0008,0090)Referring Physician's NameDiagnosis: RIS sends ReferringPhysicianName as 'DR. JANE SMITH' (single component, all caps); DICOM PN expects family^given format. Modality may forward unchanged, causing downstream FHIR Practitioner.name parsing to fail.
Fix: Normalize on perimeter: split on space/comma, identify family vs given via heuristic (last token = family for English-language names), strip honorifics ('DR.', 'M.D.'). Edge cases: hyphenated families, multi-token givens. Test against a representative sample.
-
Study Description inconsistency with Procedure Code
(0008,1030)Study DescriptionDiagnosis: RIS-emitted Procedure Code Sequence (0032,1064) says 'CT CHEST W/CONTRAST' but Modality-set Study Description (0008,1030) says 'PE PROTOCOL'. Downstream reporting templates and AI inference pipelines key off the wrong field.
Fix: Establish convention at the facility: Procedure Code Sequence is canonical from RIS; Study Description is operator-set and ignored downstream. Or: enforce StudyDescription = ProcedureCode.text on the perimeter and notify when they diverge.
When Integration Breaks
If you're hitting one of these — or a case not documented here — Saga IT's medical imaging team and Mirth Connect engineers have debugged most of them in production. Talk to us — and let us know what scenario you ran into so we can add it to this reference.