cancel
Showing results for 
Search instead for 
Did you mean: 

Xml parse error in XmlUtility.descapeStringForXml

Hello, recently got this error on auth.net response when trying to void a recurring payment:

 

2017-08-29 15:48:45,740 DEBUG [AWT-EventQueue-0] (gui.dialog.RefundTenderCreditDialog.cardSwiped()) - Card swipe event, parsed card data: CreditCard [nameOnCard=ANDERSON/CHRISTOPHER T, number=XXXXXXXXXXXX5098, track1=%BXXXXXXXXXXXXXXXX^ANDERSON/CHRISTOPHER T^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX?, track2=;XXXXXXXXXXXXXXXX=XXXXXXXXXXXXXXXXXXXX?, expireMonth=3, expireYear=25, type=null]
2017-08-29 15:48:45,755 INFO  [Thread-38] (gui.dialog.RefundTenderCreditDialog.processRequest()) - Sending authorizer request: DefaultPaymentProcessorRequest [creditCard=CreditCard [nameOnCard=ANDERSON/CHRISTOPHER T, number=XXXXXXXXXXXX5098, track1=%BXXXXXXXXXXXXXXXX^ANDERSON/CHRISTOPHER T^XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX?, track2=;XXXXXXXXXXXXXXXX=XXXXXXXXXXXXXXXXXXXX?, expireMonth=3, expireYear=25, type=VISA] requestType=VOID_REFUND, customerNumber=null, transactionNumber=108585, amount=19.95, initAmount=19.95, authorizationCode=4RWILV, purchaseType=RECURRING_INITIAL_SALE, recordNumber=1501783604, referenceNumber=40006130205, referenceData=null, processData=null, transactionCompleteDate=Tue Aug 29 15:48:05 EDT 2017, token1=null, token2=null, salesDeviceId=1]
2017-08-29 15:48:45,756 INFO  [Thread-38] (payment.authorizedotnet.AuthorizeDotNetProcessor.authorize()) - Starting processing: 1504036125756
2017-08-29 15:48:45,756 WARN  [Thread-38] (payment.authorizedotnet.AuthorizeDotNetProcessor.validatePaymentAuthorizer()) - Test mode enabled, using test environment.
2017-08-29 15:48:45,762 INFO  [Thread-38] (payment.authorizedotnet.AuthorizeDotNetProcessor.getMerchant()) - Using getGatewayServiceId2: 6n5ZeZ9EaH9 getGatewayServicePassword2: ************m6hG
2017-08-29 15:48:45,773 INFO  [Thread-38] (payment.authorizedotnet.AuthorizeDotNetProcessor.logTransactionRequest()) - -->[Type=VOID Amount=19.95 CC-type=VISA CC-number=XXXXXXXXXXXX5098 CC-ExpDate=3/25 TransactionID=40006130205 AuthCode=4RWILV]
2017-08-29 15:48:45,773 INFO  [Thread-38] (payment.authorizedotnet.AuthorizeDotNetProcessor.getMerchant()) - Using getGatewayServiceId2: 6n5ZeZ9EaH9 getGatewayServicePassword2: ************m6hG
2017-08-29 15:48:46,588 WARN  [Thread-38] (authorize.util.XmlUtility.warn()) - Exception Details-> Code:'null', Message:'null'
2017-08-29 15:48:46,589 WARN  [Thread-38] (authorize.util.XmlUtility.warn()) - Error decoding from XML, value: '1.0|3|21|An error occurred during processing.  Please try again.||P||40006130205|30F81DB854A9A7EC36FFC52B642C1600||||||||||||XXXX5098|Visa|||||
', ErrorMessage: 'null'
Caused by: java.lang.NumberFormatException: For input string: "1.0"
        at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[?:1.8.0_45]
        at java.lang.Integer.parseInt(Integer.java:580) ~[?:1.8.0_45]
        at java.lang.Integer.parseInt(Integer.java:615) ~[?:1.8.0_45]
        at net.authorize.aim.Result.createResult(Result.java:32) ~[anet-java-sdk-1.9.3.jar:?]
        at net.authorize.Merchant.postTransaction(Merchant.java:286) ~[anet-java-sdk-1.9.3.jar:?]
        at com.sonnyscontrols.payment.authorizedotnet.AuthorizeDotNetProcessor.sendRequest(AuthorizeDotNetProcessor.java:245) ~[payapi-1.0.6-RELEASE.jar:?]
        ... 4 more

 

This error is random, i could not reproduce this all the time when making a void transaction.

library: java-sdk -1.9.3

 

trace: our software calls Merchant.postTransaction() -> HttpClient.execute() -> at line 176 XmlUtility.descapeStringForXml() throws exception where looks like the very first parameter (1.0) is expected to be integer when parsing, but actually is a double so the error occures.

 

If it helps this is a void of initial recurring sale transaciton.

 

any help is appreciated. also, in my understanding, the void transaciton is actually processed fine, but since could not return a clean response, our software cannot record it as a final void.

autopilot
Contributor
18 REPLIES 18

Hi @autopilot,

 

That was a problem on our end that appeared yesterday and was also resolved yesterday. See this thread for more information.

 

In the future when you get error 21, feel free to add a routine in your code to try again. Error 21 is literally the "try again" error. On a subsequent request for the same void, we'd return success with a message indicating the transaction was already voided. 

Aaron
All Star

Aaron thanks, i will implement a duplicated request if error 21 is received.

 

However, parsing error still occures. Now we try to refund a transaction (which should be settled over night already) and expected behavior here is to receive TransNotFoudException so in this case we submit a refund request. But instead i see this:

 

2017-08-31 09:16:08,886 WARN  [Thread-53] (payment.authorizedotnet.AuthorizeDotNetProcessor.validatePaymentAuthorizer()) - Test mode enabled, using test environment.
2017-08-31 09:16:08,886 INFO  [Thread-53] (payment.authorizedotnet.AuthorizeDotNetProcessor.getMerchant()) - Using getGatewayServiceId2: 6n5ZeZ9EaH9 getGatewayServicePassword2: ************m6hG
2017-08-31 09:16:08,887 INFO  [Thread-53] (payment.authorizedotnet.AuthorizeDotNetProcessor.logTransactionRequest()) - -->[Type=VOID Amount=15.0 CC-type=MASTER_CARD CC-number=XXXXXXXXXXXX0434 CC-ExpDate=12/18 TransactionID=40006151493 AuthCode=EKDJKX]
2017-08-31 09:16:08,887 INFO  [Thread-53] (payment.authorizedotnet.AuthorizeDotNetProcessor.getMerchant()) - Using getGatewayServiceId2: 6n5ZeZ9EaH9 getGatewayServicePassword2: ************m6hG
Caused by: java.lang.NumberFormatException: For input string: "1.0"
	at java.lang.NumberFormatException.forInputString(NumberFormatException.java:65) ~[?:1.8.0_45]
	at java.lang.Integer.parseInt(Integer.java:580) ~[?:1.8.0_45]
	at java.lang.Integer.parseInt(Integer.java:615) ~[?:1.8.0_45]
	at net.authorize.aim.Result.createResult(Result.java:32) ~[anet-java-sdk-1.9.3.jar:?]
	at net.authorize.Merchant.postTransaction(Merchant.java:286) ~[anet-java-sdk-1.9.3.jar:?]
	at com.sonnyscontrols.payment.authorizedotnet.AuthorizeDotNetProcessor.sendRequest(AuthorizeDotNetProcessor.java:245) ~[payapi-1.0.6-RELEASE.jar:?]
	... 4 more

  

Hi @autopilot,

 

Let me make sure I understand the sequence here. You want to either cancel or refund the transaction, but need to know if it's settled first to determine whether to void or refund. So, you first do a void, and if that returns a transaction not found error, then you proceed to refund, correct?

 

I probably can't tell exactly why you're getting that error without seeing what the whole request/response is outside of the SDK (as sent on the wire). So I wouldn't know offhand whether we're looking at a problem in the SDK or in your code. I can give a few suggestions, though.

 

First, it looks like you're using the AIM methods. AIM is one of our older APIs (along with SIM, DPM, ARB, and CIM), and we include support for it in our SDK for backwards compatibility purposes. However, the AIM class hasn't been touched in a few years. You could try implementing the same things with our newer API that replaces all of those three letter APIs, and is all implemented in the net.authorize.xml class.

 

Another thing to try is maybe a little different sequence of events. Instead of a void attempt followed by a refund, you could try to do a transaction details request, determine if the transaction is settled or not, and then do a follow-on void or refund as appropriate.

Aaaron, yes, the sequence is correct.

 

Basically we follow this flow because it was suggested to us by some authorize.net devs a while ago (before query a trans status was implemented), thus we always submit a void request first and, if TransNotFound is returned, we submit a refund reqeust.

 

Regarding the error itself. Our code worked fine for years until customers started to report by the last week that they cannot void/refund transactions. After analyzing their cases I saw that all the failed transactions had raw track data included into request (transaction.setCreditCard();). Your response in that case showed the error "Invalid market type" so i added x_market_type field = 2 as it sounded like it's mandatory now (we never used it before as there was no difference between tracks included or non included in a transaction). After that void worked fine but sometimes we receive this xml parse error. From the string being parsed it's obvious that it happened when a response came from your server and xml parser tries to make an object out of it to return to our code. This morning we ran around of 30-40 transactions settled overnight and all them failed with the same message of parsing -1 as integer.

 

In terms of logging, what ever we have on our side i already posted above. So I can try to enable some additional logging capabilities in java-sdk-1.9.3 to see more activity?

 

About a new version: i am aware of the new API released, saw that at GitHub. The thing is we do not plan to rewrite a whole auth.net code in a near future.

Hi @autopilot,

 

 

Thanks for the additional info. Knowing that you're dealing with transactions originally created using track data, I can see what the problem is now. You're getting a specific scenario that hits a specific bug that returns the result code as "1.0" instead of "1". The java sdk expects an integer in that position, so it causes an exception.

 

The bug itself is in our system, but it hasn't yet been fixed, presumably because it only occurs in a scenario that shouldn't actually happen in production. Additionally, at least one or two people have submitted changes to the SDK, which haven't been incorporated for presumably the same reason.

 

There's a good explanation in this comment at GitHub. But, the short answer is that you're creating the initial transaction as retail (card present), but trying to void it as non-retail. While the void still ends up working, it's not a supported scenario, and it happens to run across this "1.0" bug.

 

Merchant accounts that are set up as the "retail" marketType or are otherwise operating in a retail environment should always be sending their transactions as retail, even when the card is not present. When creating a new transaction, that's done by sending x_market_type=2 and also sending x_device_type with a value of whatever is sending the transactions. If you're sending card not present transactions with a retail account, you would still be sending those fields, but you'd use a an appropriate value of x_device_type like "8" (for "website").

 

When it comes time to do a void for any transaction that was done as a retail transaction, you still need both of those fields present because it's still a retail transaction (or more correctly an operation on a retail transaction. Either way, you still want to be operating in "retail mode" for that request.) For the void, you'd send x_market_type=2 (which it sounds like you're already doing) and x_device_type of whatever's sending the transaction, like 8 for website or 10 for a virtual terminal

 

This is further explained on page 24 of the the old AIM documentation.

 

My guess is that although you're sending x_market_type, you're probably not sending x_device_type, so you're ending up in the bad part of the code. To fix it, just send an appropriate x_device_type value, which you could do in the SDK like this:

 

merchant.setDeviceType(net.authorize.DeviceType.VIRTUAL_TERMINAL);
merchant.setMarketType(net.authorize.MarketType.RETAIL);

 

 

 

OK, Aaaron, i have added x_device_type = 10 and void returns worked fine. However, we still receive this parsing error when transaction is settled. Is there another solution for it?

 

Important to note, with or without device type unit tests are passing fine.  

Hi @autopilot,

 

Please explain what you mean by "we still receive this parsing error when transaction is settled". Settlement isn't an interactive process, so when are you receiving this error and how?

The scenario is:

 

1) make an initial recurring transaction (request tokens to charge later) 

2) wait for another day (as changing Transaction Cut Off Time does not seem to do anything)

3) refund it.

 

if we process refund in the same day (usually a couple of minutes later), which is actually a VOID request, transaction is successful. if we wait for another day and in this case we will send a REFUND request, the parsing error is returned.

And you're sending both x_market_type and x_device_type with the refund request?