PAYATHON 2026

沙箱支付成功后返回 aop.ACQ.SYSTEM_ERROR 是什么原因?

支付阿杰

明确结论

aop.ACQ.SYSTEM_ERROR 表示支付宝沙箱网关在处理请求或生成响应时发生了系统异常。它不是明确的“交易失败”结果,也不能用支付页面显示成功来判断最终交易状态。

沙箱页面提示支付成功,但接口返回 code: 20000,可能是支付流程已经完成,但同步响应阶段发生了异常。此时应通过交易查询接口或异步通知中的 trade_status 确认订单是否支付成功,不能直接根据当前返回值更新订单状态。

常见原因

1. 沙箱环境临时异常

支付宝沙箱主要用于接口联调,稳定性通常不及生产环境。如果支付、回跳、同步响应或交易数据写入过程中发生临时故障,可能会返回:

code: 20000
sub_code: aop.ACQ.SYSTEM_ERROR
sub_msg: 系统异常

遇到这种情况,可以稍后使用原商户订单号查询交易状态,不要立即创建新订单,以免重复支付。

2. 支付成功与同步返回属于不同环节

支付页面显示成功,只说明收银台操作已经完成。此后还要经过多个环节:

  • 支付宝生成同步响应;
  • 浏览器跳转到 return_url;
  • 支付宝向 notify_url 发送异步通知;
  • 商户系统验签并更新订单;
  • 商户主动查询交易状态。

后续任何一个环节发生异常,都可能出现“页面显示成功,但程序没有收到正常结果”的情况。

3. 请求参数或沙箱配置不一致

如果错误持续出现,还应检查以下内容:

  • 请求是否发往沙箱网关;
  • app_id 是否属于对应的沙箱应用;
  • 应用私钥与支付宝公钥是否配套;
  • 签名方式是否一致,例如 RSA2;
  • charset 是否为 utf-8;
  • out_trade_no 是否被重复使用;
  • 支付金额、商品标题等必填字段是否合法;
  • SDK、网关地址和账号是否混入了生产环境配置。

配置有误时,接口通常会返回更明确的签名或参数错误。不过在沙箱环境中,不能因为收到 SYSTEM_ERROR 就排除配置问题。

解决步骤

第一步:保留原订单号并查询交易状态

使用支付请求中的 out_trade_no 调用 alipay.trade.query,重点检查:

trade_status

常见状态包括:

  • TRADE_SUCCESS:交易支付成功;
  • TRADE_FINISHED:交易完成;
  • WAIT_BUYER_PAY:等待买家付款;
  • TRADE_CLOSED:交易关闭。

只有交易查询结果或验签通过的异步通知表明交易成功,才能将本地订单更新为已支付。

第二步:检查异步通知

如果配置了 notify_url,需要确认:

  • 地址可以通过公网访问;
  • 请求没有被登录验证、IP 白名单或 CSRF 校验拦截;
  • 收到参数后执行了支付宝签名验证;
  • 使用通知中的 app_id、out_trade_no 和 total_amount 校验订单;
  • 处理成功后按接口要求返回 success。

支付宝可能重复发送异步通知,因此订单更新必须具备幂等性。

第三步:重试查询,不要重复支付

SYSTEM_ERROR 是系统级异常。可以对交易查询进行有限次数的延迟重试,例如等待数秒后再次查询。不要直接生成新的 out_trade_no,否则同一业务可能产生多笔交易。

第四步:检查沙箱配置

确认网关和密钥都来自同一套沙箱应用配置。沙箱请求不能使用生产环境的支付宝公钥,也不能将生产应用的 app_id 与沙箱账号混用。

如果同一请求能够稳定复现,应记录以下信息,以便排查:

  • app_id;
  • out_trade_no;
  • 接口名称;
  • 请求时间;
  • 完整响应;
  • SDK 日志或网关返回的请求标识。

记录日志时,不要输出应用私钥、用户密码或完整的敏感信息。

Python 处理示例

以下代码展示了基本处理思路。client 的初始化方式取决于实际使用的支付宝 SDK:

def handle_pay_response(client, pay_result, out_trade_no):
    if (
        pay_result.get("code") == "10000"
        and pay_result.get("trade_status") in {"TRADE_SUCCESS", "TRADE_FINISHED"}
    ):
        return {
            "paid": True,
            "source": "pay_response",
            "result": pay_result,
        }

    if (
        pay_result.get("code") == "20000"
        or pay_result.get("sub_code") == "aop.ACQ.SYSTEM_ERROR"
    ):
        query_result = client.execute(
            "alipay.trade.query",
            biz_content={
                "out_trade_no": out_trade_no,
            },
        )

        trade_status = query_result.get("trade_status")

        if (
            query_result.get("code") == "10000"
            and trade_status in {"TRADE_SUCCESS", "TRADE_FINISHED"}
        ):
            return {
                "paid": True,
                "source": "trade_query",
                "result": query_result,
            }

        if trade_status == "WAIT_BUYER_PAY":
            return {
                "paid": False,
                "pending": True,
                "result": query_result,
            }

        return {
            "paid": False,
            "pending": False,
            "result": query_result,
        }

    return {
        "paid": False,
        "pending": False,
        "result": pay_result,
    }

不同 SDK 的方法名称和返回结构可能不同,调用时应以当前 SDK 的接口定义为准。处理原则不变:收到 aop.ACQ.SYSTEM_ERROR 后,使用原 out_trade_no 查询真实的交易状态。

注意事项

返回数据中的以下字段:

buyer_pay_amount: 0.00
receipt_amount: 0.00
invoice_amount: 0.00

不能单独证明买家没有付款。它们可能只是异常响应中的默认值,并不代表有效的交易金额结果。

浏览器同步跳转也不能作为支付成功的唯一依据。可靠的订单状态应来自:

  1. 验签通过的异步通知;
  2. alipay.trade.query 的成功查询结果;
  3. 对订单号、金额、应用 ID 和交易状态的完整校验。

如果查询结果为 TRADE_SUCCESS,可以按支付成功处理。如果持续查询不到交易,或者查询仍然返回系统异常,则更可能是沙箱服务异常或配置问题。此时应保留请求信息,稍后重试。

备注:内容仅供参考。