Skip to content

Repeating primitive with extensions but no values omits the null-padded value array #1631

Description

@oliveregger

When every entry of a repeating primitive element carries only an extension (or id) and no value, SUSHI emits the _element array without the parallel value array. Per the FHIR JSON spec the value array should still be present, null-filled, so the two arrays align.

SUSHI already gets this right as soon as one entry has a value — it emits "given": ["Xavier", null] alongside "_given": [null, {...}]. Only the all-values-absent case drops the value array, so this looks like a gap in an otherwise-correct code path rather than a design decision.

Version: SUSHI v3.20.0 (implements FHIR Shorthand specification v3.0.0), fhirVersion: 4.0.1.

Steps to reproduce

sushi-config.yaml:

canonical: http://example.org/repro
fhirVersion: 4.0.1
FSHOnly: true

input/fsh/repro.fsh:

Alias: $display = http://hl7.org/fhir/StructureDefinition/display

// 1. Repeating primitive, extension but NO value anywhere in the array.
Instance: NoValues
InstanceOf: Patient
Usage: #example
* name[0].given[0].extension[0].url = $display
* name[0].given[0].extension[0].valueString = "ext on given[0]"

// 2. Same, but one sibling entry has a value.
Instance: SomeValues
InstanceOf: Patient
Usage: #example
* name[0].given[0] = "Xavier"
* name[0].given[1].extension[0].url = $display
* name[0].given[1].extension[0].valueString = "ext on given[1]"

// 3. Non-repeating primitive, extension but no value.
Instance: NonRepeating
InstanceOf: Patient
Usage: #example
* name[0].family.extension[0].url = $display
* name[0].family.extension[0].valueString = "ext on family"

// 4. Repeating primitive with an id (not an extension) and no value.
Instance: NoValuesId
InstanceOf: Patient
Usage: #example
* name[0].given[0].id = "given-0"

Then sushi . and inspect name[0] in each generated instance.

Actual

// 1. NoValues — value array missing entirely
{"_given":[{"extension":[{"url":"…/display","valueString":"ext on given[0]"}]}]}

// 2. SomeValues — correct, arrays aligned and null-padded
{"given":["Xavier",null],"_given":[null,{"extension":[{"url":"…/display","valueString":"ext on given[1]"}]}]}

// 3. NonRepeating — correct, no array involved
{"_family":{"extension":[{"url":"…/display","valueString":"ext on family"}]}}

// 4. NoValuesId — same gap, with id rather than extension
{"_given":[{"id":"given-0"}]}

Expected

Cases 1 and 4 should null-pad the value array the same way case 2 does:

// 1.
{"given":[null],"_given":[{"extension":[{"url":"…/display","valueString":"ext on given[0]"}]}]}

// 4.
{"given":[null],"_given":[{"id":"given-0"}]}

Cases 2 and 3 are already correct and are included only as controls.

Spec reference

FHIR R4 §JSON Representation of Primitive Elements:

In the case where the primitive element may repeat, it is represented in two arrays. JSON null values are used to fill out both arrays so that the id and/or extension are aligned with the matching value in the first array

Note: when one of the repeating elements has no value, it is represented in the first array using a null. When an element has a value but no extension/id, the second array will have a null at the position of that element.

The second sentence covers this case directly: the repeating element has no value, so it should be represented in the first array using a null. The spec's worked example happens to show a mixed array, which may be why the all-absent case was missed.

Why it matters

We author SDC template-based $extract templates (sdc-questionnaire-templateExtractValue), where a directive is an extension on an element that deliberately has no value — the value is produced at extraction time. On repeating primitives such as HumanName.given and Address.line that is exactly case 1.

Uploading such a questionnaire to HAPI FHIR (tested on 8.10.0 and on hapi.fhir.org 8.11.16-SNAPSHOT) returns 201/200 with no OperationOutcome, but the stored resource has silently dropped those extensions.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions