Bug #4877

AssertionError: TypeError [ERR_INVALID_ARG_TYPE]: The "data" argument must be of type string or an instance of Buffer, TypedArray, or DataView. Received an instance of Array

Added by Michael Kay about 1 month ago. Updated 15 days ago.

In Progress
Start date:
Due date:
% Done:


Estimated time:
Applies to JS Branch:
Fix Committed on JS Branch:
Fixed in JS Release:
SEF Generated with:
Contact person:
Additional contact persons:


We're getting this message from a number of the Node.js API tests, specifically

async-trans-015, -016, -020, -021, -022, -025, -026; sync-trans-015, -016, -020, -021

The stack trace shows

Received an instance of Array
   at Object.writeFileSync (fs.js:1409:5)
   at Object.writeFileSync (/Users/mike/GitHub/saxon-js-enterprise/build/temp/js/build/SaxonJS2N.debug.js:19959:11)
   at (/Users/mike/GitHub/saxon-js-enterprise/build/temp/js/build/SaxonJS2N.debug.js:26532:21)
   at $$onCompletion$$$ (/Users/mike/GitHub/saxon-js-enterprise/build/temp/js/build/SaxonJS2N.debug.js:13950:25)

and it's caused because we pass an array containing an XdmString to the "data" argument of fs.writeFileSync, rather than passing the underlying string.

There's a suggestion at

that this might reflect a change in a recent version of the fs library (the spec suggests that any Object with a toString() method is accepted).

We're calling fs.writeFileSync() from a save() function; the user can supply a save() function, but if they don't, we supply our own. The documentation says that the format of the value passed to the save() function depends on the value of resultForm. In these tests there is no user-supplied resultForm option, so it ought to default to a Javascript string; this doesn't appear to be the case. But we also need to consider what happens if there is a user-supplied resultForm, in which case the system-supplied save() method might have to cope with different possibilities.


#1 Updated by Michael Kay about 1 month ago

The documentation for the save() callback says

The value to be saved. The format of this value is controlled by the value of options.resultForm: the default is to convert the value to JavaScript following the rules in XDM to JavaScript Conversion.

But this doesn't appear to be the case. The save() method is called from Expr.js#1875 as [Atomic.XS.string.fromString(out)] (an array containing a single XdmString) or from Expr.js#1886 as builder.result() (generally an array of Nodes).

As far as I can see, we take account of resultForm only for setting the principalResult, not for setting secondary results.

For fn:transform(), we supply a save() function that writes the supplied value directly to the output resultDocuments map. For this case, using an XDM item is appropriate, because we're returning a result to XPath/XSLT code. For SaxonJS.transform(), however, returning a value that's convenient for Javascript use makes more sense. And when we're writing the serialized result to file store, it always wants to be a Javascript string.

#2 Updated by Michael Kay about 1 month ago

As an immediate fix, I suggest that where the destination is "serialized", we should always pass the serialized value to the save() method as a Javascript string, and it's up to the save() method what to do with it.

In the case where destination="file", our save() method writes the string to a method such as fs.writeFileSync().

In the fn:transform case, our save() method wraps it as an XDMString and puts the result in the map returned to the fn:transform() caller.

In the case where the user wants the result added to the SaxonJS.transform() result map, our save() method converts it to the form defined by the resultForm option.

#3 Updated by Michael Kay about 1 month ago

  • Status changed from New to In Progress

With these changes, the relevant tests now pass. There's a need for further testing to ensure (a) no side-effects on the browser API tests, and (b) no side-effects on fn:transform(). There's also a need to clarify the documentation, and perhaps to tidy up behaviour in other cases that aren't being tested. For example, the Node.js API tests currently include no tests for a user-specified deliverResultDocument option.

#4 Updated by Debbie Lockett 15 days ago

  • Applies to JS Branch 2 added

Please register to edit this issue

Also available in: Atom PDF Tracking page