Question Kevin Mayfield · Feb 20, 2025

MAXSTRING error on conversion to JSON in FHIR R4 DTL

I'm working on FHIR project and using this code to convert an incoming request to FHIR 

Method OnRequest(request As HS.FHIRServer.Interop.Request, Output response As HS.FHIRServer.Interop.Response) As %Status

{

    #dim tSC As %Status = $$$OK

    Try {

        // Process incoming request

        set stream = ##class(HS.SDA3.QuickStream).%OpenId(request.QuickStreamId)

        set bundle = ##class(HS.FHIR.DTL.vR4.Model.Resource.Bundle).FromJSON(stream,"vR4")


It's working ok but when I include a realistic PDF in a FHIR Binary resource (contained in the Bundle) I get a MAXSTRING error. 
Looking at the documentation for HS.FHIR.DTL.vR4.Model.Resource.Binary, I wondering if MAXLEN setting for data is missing and data MAXLEN = 50. 
 

Property contentType As %String(MAXLEN = 1000000, XMLNAME = "contentType", XMLPROJECTION = "ATTRIBUTE") [ Required ];
Property data As %Binary(XMLNAME = "data", XMLPROJECTION = "ATTRIBUTE");
 

Product version: HealthShare 2024.1
$ZV: IRIS for Windows (x86-64) 2024.1.3 (Build 456U) Thu Jan 9 2025 12:47:03 EST

Comments

Kevin Mayfield · Feb 20, 2025

Error 

ERROR <Ens>ErrBPTerminated: Terminating BP ProcessMessage # due to error: ERROR #5002: ObjectScript error: <MAXSTRING>%GetNext+12^%Iterator.Object.1
> ERROR #5002: ObjectScript error: <MAXSTRING>%GetNext+12^%Iterator.Object.1

Stack 

  • ^%GetNext+12^%Iterator.Object.1^1
  • e^FromJSONHelper+17^HS.FHIR.DTL.Util.JSON.Adapter.1^1
  • e^FromJSONHelper+98^HS.FHIR.DTL.Util.JSON.Adapter.1^1
  • e^FromJSONHelper+80^HS.FHIR.DTL.Util.JSON.Adapter.1^1
  • e^FromJSON+9^HS.FHIR.DTL.Util.JSON.Adapter.1^1
  • e^OnRequest+5^RIE.GLH.FHIR.Process.ProcessMessage.1^1
  • e^MessageHeaderHandler+19^RIE.GLH.FHIR.Process.ProcessMessage.1^1
  • e^MessageHeaderHandler+110^Ens.Actor.1^1

     

0
Ashok Kumar T  Feb 21, 2025 to Kevin Mayfield

Hello @Kevin Mayfield 

%GetNext retrieves values from the JSON object/array and assigns them to a local variable. However, the BLOB/streams exceed the maximum local length (3641144), MAXLEN doesn't cause the issue because it's a registered object, and the values are currently stored in memory. Therefore, AFAIK FromJSON is not suitable for handling such a large dataset.

0
Kevin Mayfield  Feb 21, 2025 to Ashok Kumar T

Any ways around this? It will be easier for the other developers to keep a like for like payload to OML_021 and ORU_R01 (obvious answer might be use HL7 v2 instead).
But I think I can answer this via attachments in via another API (POST /Binary)
I'll probably still have this need for outgoing payloads to a national system but handcrafting that might work.
 

0
Ashok Kumar T  Feb 23, 2025 to Kevin Mayfield

Hello @Kevin Mayfield 

Instead FromJSON() write a custom class to parse the Binary Resource and set it into the FHIR model class. 

Here I convert the the data (which is the Binary resource -pdf or anything) to stream and set it in the data field of the HS.FHIR.DTL.vR4.Model.Resource.Binary class

ClassMethod SetBinaryR4(json As%DynamicObject)
{
    Set obj = ##class(HS.FHIR.DTL.vR4.Model.Resource.Binary).%New()
    Set obj.contentType = json.contentType
    #; convert to stream to prevent from the <MAXSTRING> error Set dataAsStrm = json.%Get("data",,"stream")
    Set obj.data = dataAsStrm
    Set obj.id = json.id
    
    #; set binary data element as stream for "Binary" resource. ZWrite obj.data.Read()
}

Thanks!

0
Kevin Mayfield  Feb 26, 2025 to Ashok Kumar T

Many thanks. 
I think I might be able to do a work around along those lines. 
1. replace the base64 entries with a placeholder and save the base64 entries as new QuickStreams. 
2. do the DTL transforms
3. put back the base64 entries just before I call out to the FHIR operations.

0
Steven Hobbs  Feb 25, 2025 to Ashok Kumar T

The %GetNext() method calls in the HS.FHIR.DTL.Util.JSON.Adapter class must have been written using 2 arguments and looking something like
   while iter.%GetNext(.Name, .Value) {

When the two argument form of %GetNext encounters a %String value, it always return an ObjectScript string in the 2nd argument which limits the string length to 3641144 characters.  However, there is a 3 argument form of %GetNext(.Name, .Value, .Type) which never signals <MAXSTRING>.  If a string element in a %DynamicArray/%DynamicObject (%DA/%DO) element is too long then a %Stream oref is returned in the .Value argument while the .Type argument variable contains the value "string".  If .Type is not "string" but is instead "oref" then that tells you the element in the %DA/%DO was originally a %Stream oref and not a %String value.  See the Class Reference web page describing the %Iterator.Object class which will explain how to use the 3rd .Type argument to solve ambiguities that occur when %GetNext must convert the %DA/DO value returned in .Value to an ObjectScript value different from the original JSON value.

You should suggest to HealthShare developers that their HS.FHIR.DTL.Util.JSON.Adapter class (and maybe some other classes) should be using the 3 argument form of %GetNext(.Name,.Value,.Type) instead of the 2 argument form %GetNext(.Name,.Value) in order to eliminate possible <MAXSTRING> and <MAXNUMBER> errors.

0
Steven Hobbs  Feb 25, 2025 to Steven Hobbs

You mention that you are using IRIS version 2024.1.  The 3 argument form of %GetNext first appeared in IRIS version 2024.3 so it is possible that HealthShare is already using the 3 argument %GetNext method.

0
Kevin Mayfield  Feb 26, 2025 to Steven Hobbs

Have been away from healthshare for a few years, so I'll look into what you said and then probably raise a wrc.
many thanks

0