itunes-iap
itunes-iap copied to clipboard
IndexError: list index out of range
Hello. We got this problem with itunes-iap 2.5
[2017-11-08 15:00:20,934] [ERROR] views.py:3308 - root: list index out of range Traceback (most recent call last): File "/home/django/atcontrol/releases/1510061996/mayak/api_v3/views.py", line 3243, in purchase_ios log.info(res.receipt.last_in_app) File "/home/django/atcontrol/releases/1510061996/venv/local/lib/python2.7/site-packages/itunesiap/receipt.py", line 245, in last_in_app self.in_app, key=lambda x: x['original_purchase_date_ms'])[-1] IndexError: list index out of range
part of view from our django rest framework api with problem line of code
@api_view(['POST'])
def purchase_ios(request):
log.info('purchase_ios (%s) POST: %s' % (request.user, request.POST))
try:
res = itunesiap.verify(request.POST.get("receipt", None), settings.ITUNES_PASSWORD, verify_ssl=False,
use_production=True, use_sandbox=True)
log.info(res.receipt.last_in_app)
...
Any ideas what's wrong?
Hello. Do you have any expected result? I want to know there was actually no in_apps in the receipt or itunesiap failed to bring the data even if they were in receipts.
I'm also experiencing a similar IndexError in one of my api views:
# ...
if sandbox:
with itunesiap.env.sandbox:
try:
response = itunesiap.verify(raw_data, use_sandbox=True)
return True, response
except (ItunesServerNotAvailable, ItunesServerNotReachable):
no_response = True
except itunesiap.exc.InvalidReceipt as exc:
error = exc.description
Sentry actually indicates the error/exception being raised when exiting the contextmanager:
itunesiap/environment.py in __exit__ at line 42
self._ctx_id = len(self._stack)
self.push()
return self
def __exit__(self, exc_type, exc_value, tb):
self._stack.pop(self._ctx_id) # this line
Any clues on what might be happening?
I've come across the same issue. In my case it is caused because 'in_app' list can be empty.
return response.receipt.last_in_app
File "/home/vagrant/.local/share/virtualenvs/Server/lib/python3.6/site-packages/itunesiap/receipt.py", line 310, in last_in_app
self.in_app, key=lambda x: x['original_purchase_date_ms'])[-1]
IndexError: list index out of range
https://stackoverflow.com/questions/36010595/itunes-reciept-validation-in-app-empty
An empty in_app array indicates that StoreKit has not recorded any transactions for that user yet. It may be that the application receipt has not yet been updated. When this happens, your app can inform the user that the receipt does not appear current and ask whether to refresh it. Upon user agreement, your app should use the SKReceiptRefreshRequest class to update the receipt. At this point, if StoreKit has recorded a purchase for the user, your app receipt will show it in in_app. See Refreshing the App Receipt for more information on how to update a receipt.
It occurred to me, that the algo used to retrieve last_in_app is wrong. There can be several transactions having the same original_purchase_date. For example, it's true for subscriptions which share the same original_transaction_id:
{
"quantity": "1",
"product_id": "com.subscription",
"transaction_id": "1000000581056268",
"original_transaction_id": "1000000506536546",
"purchase_date": "2019-02-28 11:16:27 Etc/GMT",
"purchase_date_ms": "1551352587000",
"purchase_date_pst": "2019-02-28 03:16:27 America/Los_Angeles",
"original_purchase_date": "2019-02-28 11:11:27 Etc/GMT",
"original_purchase_date_ms": "1551352287000",
"original_purchase_date_pst": "2019-02-28 03:11:27 America/Los_Angeles",
"expires_date": "2019-02-28 11:21:27 Etc/GMT",
"expires_date_ms": "1551352887000",
"expires_date_pst": "2019-02-28 03:21:27 America/Los_Angeles",
"web_order_line_item_id": "1000000042979542",
"is_trial_period": "false",
"is_in_intro_offer_period": "false"
},
{
"quantity": "1",
"product_id": "com.subscription",
"transaction_id": "1000000581056278",
"original_transaction_id": "1000000506536546",
"purchase_date": "2019-02-28 11:21:27 Etc/GMT",
"purchase_date_ms": "1551352887000",
"purchase_date_pst": "2019-02-28 03:21:27 America/Los_Angeles",
"original_purchase_date": "2019-02-28 11:11:27 Etc/GMT",
"original_purchase_date_ms": "1551352287000",
"original_purchase_date_pst": "2019-02-28 03:11:27 America/Los_Angeles",
"expires_date": "2019-02-28 11:26:27 Etc/GMT",
"expires_date_ms": "1551353187000",
"expires_date_pst": "2019-02-28 03:26:27 America/Los_Angeles",
"web_order_line_item_id": "1000000042979655",
"is_trial_period": "false",
"is_in_intro_offer_period": "false"
},
So, the correct way to sort the transactionы is to sort them by "purchase_date_ms" instead. Actually, the key may need to be even more complex:
@staticmethod
def _get_transaction_date_ms(in_app):
try:
return in_app.cancellation_date_ms
except MissingFieldError:
pass
try:
return in_app.purchase_date_ms
except MissingFieldError:
pass
return in_app.original_purchase_date_ms
@maccinza @aaksarin Because I don't work for in-app-purchase anymore, it is hard to check issues. Can anyone share a full receipt with this error please?
@evgenybf I tried to reproduce the issue with your example but it passed tests. Would you share full receipt please?
A patch with test cases are also very appreciated :)
I'm having the same issue - while it passes all sandbox tests, verifying some real-world subscription transactions returns an empty in_app array, which errors out when we try to access response.receipt.last_in_app.
I haven't been able to replicate the conditions under which we get the empty in_app.
It's an auto-renewing subscription, if that makes any difference - might be related to this: https://developer.apple.com/library/archive/technotes/tn2413/index.html#//apple_ref/doc/uid/DTS40016228-CH1-RECEIPT-MY_APP_VALIDATES_ITS_RECEIPT_WITH_THE_APP_STORE_VIA_PAYMENTQUEUE_UPDATEDTRANSACTIONS__AFTER_A_SUCCESSFUL_PURCHASE__HOWEVER__THE_RETURNED_RECEIPT_CONTAINS_AN_EMPTY_IN_APP_ARRAY_RATHER_THAN_THE_EXPECTED_PRODUCTS
While it'd be good to get at the deeper issue, a partial solution would be to simply return None for last_in_app when the in_app list is empty.