Hacktoberfest 2026:维护者为十月标记出来的 issue,仍然开放、适合新手。 浏览 Hacktoberfest issue

StripeError exceptions are not pickleable

未关闭
#1,941 1 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看

维护者通常 2 天内回复

还没有人认领这个 Issue。

评估

难度
4/5
预计耗时
3-5 天
新手友好度
55/100
Issue 类型
缺陷
描述清晰度
基本清楚
活跃度
活跃
技术栈
python

调研方向

Start by locating StripeError and its subclasses, especially InvalidRequestError, and read how their constructors and exception arguments are handled. Reproduce the pickle round trip in the issue with Python 3.12, then inspect or add tests for serializing and deserializing the error. Done means the round trip succeeds for InvalidRequestError and its required fields are preserved.

由索引模型根据 Issue 内容生成。

描述

bug
Describe the bug

StripeError exceptions can't be serialized and deserialized using pickle.
We use Celery and the errors returned by Stripe API calls can't be serialized and can't be caught outside of the async task.

To Reproduce
from stripe import StripeClient, InvalidRequestError
import pickle

try:
    StripeClient("myapikey").v1.prices.list({"expand": ["notexpandable"]})
except InvalidRequestError as e:
    pickle.loads(pickle.dumps(e))  # TypeError: InvalidRequestError.__init__() missing 1 required positional argument: 'param'
Expected behavior

InvalidRequestError can pickled:

pickle.loads(pickle.dumps(e))

raises no error

Code snippets

OS

Linux

Language version

Python 3.12

Library version

stripe-python v15.6.1

API version

2026-02-25.clover

Additional context

I suggest to not call the super().__init__() of the StripeError class. When the exception is pickled, it is deconstructed and reconstructed using the exc.args attribute, only the arguments passed to the parent class will be included in exc.args. For example:

class StripeError(Exception):
    def __init__(message, http_body, http_status):
        super().__init__(message)
        ....


StripeError("message", {"response": "body"}, 400).args  # ("message",)   all other arguments are not included

Solution:

class StripeError(Exception):
    def __init__(message, http_body, http_status):
        # do not call __init__ of Exception
        ....

StripeError("message", {"response": "body"}, 400).args  # ("message",  {"response": "body"}, 400)

But still if we pass keyword arguments:

class StripeError(Exception):
    def __init__(message, http_body, http_status):
        # do not call __init__ of Exception
        ....

# keyword arguments are not include in exception args
StripeError("message", http_body={"response": "body"}, status=400).args  # ("message",)

We could think of passing all parameters to the parent class, but:

class StripeError(Exception):
    def __init__(message, http_body, http_status):
        # pass all parameters to parent class
        super().__init__(message, http_body, http_status)

# instances of StripeError are fixed
StripeError("message", http_body={"response": "body"}, status=400).args  # ("message",  {"response": "body"}, 400)

# but what if we subclass again?
class InvalidRequesError(StripeError):
    def __init__(message, http_body, http_status, param):
        # pass all parameters to parent class
        super().__init__(message, http_body, http_status)
        self.param = param

# now we have an issue again
InvalidRequesError("message", {"response": "body"}, 400, "param").args  # ("message",  {"response": "body"}, 400)   param is missing

One possible solution, never call Exception.init() and accept *args which will be forwarded to the parent class:

class StripeError(Exception):
    # accept *args
    def __init__(message, http_body, http_status, *args):
        # do not call Exception.__init__()
        ...

# instances of StripeError are fixed
StripeError("message", {"response": "body"}, 400).args  # ("message",  {"response": "body"}, 400)

class InvalidRequesError(StripeError):
    def __init__(message, http_body, http_status, param):
        # pass all parameters to parent class
        super().__init__(message, http_body, http_status, param)
        self.param = param

# now also subclasses are fixed
InvalidRequesError("message", {"response": "body"}, 400, "param").args  # ("message",  {"response": "body"}, 400, "param")

If we want to subclass InvalidRequestError it will also have to accept *args and forward everything as positional argument to its parent class.

主要语言
Python
星标
2.1k
派生
538
平均合并
2 天 16 小时
30 天内合并 PR
28

环境准备

从这里开始

  1. 先读完整个 Issue,再读项目的贡献指南。
  2. 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
  3. Fork 仓库,在一个分支上完成修改。
  4. 提交 Pull Request,并在描述里引用这个 Issue 编号。

stripe/stripe-python 的其他 Issue

查看 stripe/stripe-python 的全部 Issue

相似的 Issue

更多 Python Issue

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。