Sepasoft WS XML Body Processing

I am creating a Sepasoft Web Service endpoint to receive ERP data. Ignition 8.1.17, WS 3.81.1 (b2022042818).

When I have a single record in the records section, there is no issue; the XML is automatically converted to a dict by Sepasoft’s module. When I add a second record, however, the call fails. I cannot even get the body to print at this point and receive this error:
do_POST TypeError: info(): 1st arg can’t be coerced to String

Any suggestions on how to work through this?

The body is arriving in a format like this:

<?xml version="1.0" encoding="UTF-8"?>
<processOrder>
    <RECORDS>
        <RECORD>
            <ORDER>1</ORDER>
            <ATTRIB1>Test 1-1</ATTRIB1>
            <ATTRIB2>Test 1-2</ATTRIB2>
        </RECORD>
        <RECORD>
            <ORDER>2</ORDER>
            <ATTRIB1>Test 2-1</ATTRIB1>
            <ATTRIB2>Test 2-2</ATTRIB2>
        </RECORD>
    </RECORDS>
</processOrder>

info(): 1st arg can’t be coerced to String

That sounds like an internal programming error in the module, not an issue with anything you’re doing. If there’s a full stacktrace, it would help prove that.

Stack trace:

com.inductiveautomation.ignition.common.script.JythonExecException: Traceback (most recent call last): File "", line 29, in do_POST File "", line 281, in handleWebServicePOST_v1 File "", line 281, in handleWebServicePOST_v1 File "", line 573, in processProcessOrder_v1 TypeError: info(): 1st arg can't be coerced to String
at org.python.core.Py.TypeError(Py.java:236)
at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:213)
at org.python.core.PyReflectedFunction.throwBadArgError(PyReflectedFunction.java:316)
at org.python.core.PyReflectedFunction.throwError(PyReflectedFunction.java:325)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:171)
at org.python.core.PyReflectedFunction.__call__(PyReflectedFunction.java:208)
at org.python.core.PyObject.__call__(PyObject.java:477)
at org.python.core.PyObject.__call__(PyObject.java:481)
at org.python.core.PyMethod.__call__(PyMethod.java:141)
at org.python.pycode._pyx6909.processProcessOrder_v1$14(:575)
at org.python.pycode._pyx6909.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:150)
at org.python.core.PyFunction.__call__(PyFunction.java:426)
at org.python.pycode._pyx6909.handleWebServicePOST_v1$5(:295)
at org.python.pycode._pyx6909.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:187)
at org.python.core.PyFunction.__call__(PyFunction.java:449)
at org.python.pycode._pyx6919.do_POST$1(:32)
at org.python.pycode._pyx6919.call_function()
at org.python.core.PyTableCode.call(PyTableCode.java:173)
at org.python.core.PyBaseCode.call(PyBaseCode.java:306)
at org.python.core.PyFunction.function___call__(PyFunction.java:474)
at org.python.core.PyFunction.__call__(PyFunction.java:469)
at org.python.core.PyFunction.__call__(PyFunction.java:464)
at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:831)
at com.inductiveautomation.ignition.common.script.ScriptManager.runFunction(ScriptManager.java:813)
at com.inductiveautomation.ignition.gateway.project.ProjectScriptLifecycle$TrackingProjectScriptManager.runFunction(ProjectScriptLifecycle.java:806)
at com.sepasoft.webservice.gateway.provider.WSProvider.processRESTRequest(WSProvider.java:218)
at com.sepasoft.webservice.gateway.provider.WSProvider.processWSRequest(WSProvider.java:155)
at com.sepasoft.webservice.gateway.provider.WSProvider.checkEditionAndProcessWSRequest(WSProvider.java:127)
at com.sepasoft.webservice.gateway.provider.WSProvider.doPost(WSProvider.java:95)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:707)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at com.inductiveautomation.ignition.gateway.bootstrap.MapServlet.service(MapServlet.java:86)
at org.eclipse.jetty.servlet.ServletHolder$NotAsync.service(ServletHolder.java:1450)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:799)
at org.eclipse.jetty.servlet.ServletHandler$ChainEnd.doFilter(ServletHandler.java:1631)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:548)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:600)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:235)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:1624)
at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1440)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:501)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:1594)
at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1355)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at com.inductiveautomation.catapult.handlers.RemoteHostNameLookupHandler.handle(RemoteHostNameLookupHandler.java:121)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.rewrite.handler.RewriteHandler.handle(RewriteHandler.java:322)
at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:59)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:146)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
at org.eclipse.jetty.server.Server.handle(Server.java:516)
at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:487)
at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:732)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:479)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:277)
at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:338)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:315)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:173)
at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:131)
at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:409)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:883)
at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:1034)
at java.base/java.lang.Thread.run(Unknown Source)
Caused by: org.python.core.PyException: TypeError: info(): 1st arg can't be coerced to String
... 76 common frames omitted

Are you calling info with a custom logger on line 573 of processProcessOrder_v1? Try wrapping your argument to info with Python’s builtin str, e.g. logger.info(str(myArg))

:man_facepalming:

Yeah… not explicitly cast.