支付宝付款正常但退款出现 aop.ACQ.SYSTEM_ERROR
结论
aop.ACQ.SYSTEM_ERROR 通常表示支付宝退款链路出现了临时系统异常,或者退款服务暂时不可用。付款正常不代表退款也一定正常,因为支付和退款使用不同的接口,还会经过不同的交易状态、资金渠道、权限和风控校验。
如果错误只是偶发出现,应先按”结果未知”处理:查询退款结果,再使用原退款请求号重试。不要立即生成新的退款请求号反复提交,以免造成重复退款。
如果连续数天无法退款,而且所有订单都有相同问题,就需要检查商户权限、交易状态、资金渠道、请求参数和证书配置。同时保留支付宝返回的 code、sub_code、sub_msg 及请求时间,联系支付宝技术支持排查。
常见原因
1. 支付宝退款服务临时异常
错误信息中的:
Service Currently Unavailable
aop.ACQ.SYSTEM_ERROR
通常表示请求已经到达支付宝网关,但退款服务或相关依赖没有正常完成处理。问题可能来自短时抖动,也可能只影响部分商户、部分交易或特定资金渠道。
接口报错不一定意味着退款失败。退款可能已经受理,只是在返回响应时发生了异常。因此,不要直接把订单恢复为”未退款”状态,也不要用新的请求号再次发起退款。
2. 网关封装错误时丢失了详细信息
业务系统中的 ERROR_GATEWAY 很可能是支付组件或网关层自行定义的错误,并非支付宝接口返回的原始错误码。
应记录支付宝返回的完整内容,至少包括:
code
msg
sub_code
sub_msg
trade_no
out_trade_no
refund_fee
gmt_refund_pay
如果日志里只有一行 aop.ACQ.SYSTEM_ERROR,现有信息不足以判断具体原因。需要检查支付 SDK 或网关是否覆盖、截断了原始响应。
3. 交易状态不允许退款
以下情况也可能导致退款请求失败:
- 原交易不存在,或者订单号填写错误;
- 交易尚未成功;
- 交易已经关闭;
- 已退款金额与本次退款金额之和超过实付金额;
- 退款期限、交易产品或资金渠道存在限制;
- 同一退款请求号此前已经使用,但本次提交的参数与原请求不一致。
这类问题一般会返回更具体的 sub_code。如果中间网关没有完整处理响应,业务系统也可能只看到系统错误。
4. 商户配置或权限发生变化
支付成功但退款失败,也可能是退款侧配置出现了问题,例如:
- 应用与商户账号的绑定关系发生变化;
- 应用退款权限、产品签约状态或商户状态异常;
- 使用了错误的
app_id、私钥、证书或支付宝公钥; - 支付请求和退款请求使用了不同的配置或运行环境;
- 更新证书后,部分服务器仍在使用旧配置;
- 商户资金状态异常,或退款资金渠道受限。
签名和证书错误通常会返回更明确的错误码。因此,只有在所有退款都持续失败时,才需要重点检查这些配置。
建议的排查步骤
第一步:确认影响范围
需要分别确认:
- 是单笔交易失败,还是所有交易都失败;
- 是偶发失败,还是每次调用都失败;
- 全额退款和部分退款是否都有问题;
- 不同支付时间、支付渠道和金额的订单是否表现一致;
- 多台服务器是否都出现相同问题。
如果只有少量请求偶发失败,更可能是支付宝链路的临时异常。如果所有请求都稳定失败,则应重点检查账号、接口权限、请求参数和配置。
第二步:保存完整请求和响应
日志中应包含:
API: alipay.trade.refund
app_id
trade_no 或 out_trade_no
out_request_no
refund_amount
请求时间
支付宝响应的 code、msg、sub_code、sub_msg
网关请求 ID 或 trace ID
不要在日志中记录商户私钥、应用私钥、完整身份证号等敏感信息。
还要确认系统实际调用的是:
alipay.trade.refund
同时检查支付和退款是否使用同一个正式环境、同一个 app_id 以及同一套签名配置。
第三步:先查询退款结果
遇到 SYSTEM_ERROR、请求超时或连接中断时,应先调用:
alipay.trade.fastpay.refund.query
查询时使用原退款请求中的 out_request_no,确认退款是否已经成功。
根据查询结果处理本地状态:
- 查询确认退款成功:更新本地退款状态,不再重试;
- 查询确认退款失败或记录不存在:使用原
out_request_no重试; - 查询结果仍不明确:保持”退款处理中”状态,稍后再次查询;
- 不要因为一次系统错误就生成新的
out_request_no。
第四步:核对退款参数
重点检查:
trade_no / out_trade_no
refund_amount
out_request_no
refund_reason
需要注意:
trade_no和out_trade_no至少提供一个;refund_amount不得超过可退款金额;- 金额应使用十进制字符串,避免直接使用浮点数计算;
- 同一次退款重试时,
out_request_no和退款金额必须保持一致; - 多次部分退款时,每次退款都必须使用不同的
out_request_no。
金额建议使用 BigDecimal:
BigDecimal refundAmount = new BigDecimal("10.00");
String amount = refundAmount.setScale(2, RoundingMode.UNNECESSARY).toPlainString();
不要使用:
double refundAmount = 0.1 + 0.2;
浮点数可能产生精度误差,导致提交的金额与预期不一致。
Java 调用示例
下面的示例只展示核心处理方式。具体类名和构造参数应以项目当前使用的支付宝 Java SDK 为准。
AlipayTradeRefundRequest request = new AlipayTradeRefundRequest();
AlipayTradeRefundModel model = new AlipayTradeRefundModel();
model.setOutTradeNo("ORDER_202609090001");
model.setRefundAmount("10.00");
model.setOutRequestNo("REFUND_202609090001");
model.setRefundReason("用户申请退款");
request.setBizModel(model);
AlipayTradeRefundResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
// 退款接口调用成功。
// 仍建议根据业务需要保存 trade_no、refund_fee 等返回字段。
markRefundSuccess(response);
} else {
log.warn(
"Alipay refund failed: code={}, msg={}, subCode={}, subMsg={}, body={}",
response.getCode(),
response.getMsg(),
response.getSubCode(),
response.getSubMsg(),
response.getBody()
);
if ("aop.ACQ.SYSTEM_ERROR".equals(response.getSubCode())) {
// 结果可能不明确,不要直接创建新的退款请求。
markRefundProcessing();
queryRefundResult("ORDER_202609090001", "REFUND_202609090001");
} else {
markRefundFailed(response.getSubCode(), response.getSubMsg());
}
}
退款查询示例:
AlipayTradeFastpayRefundQueryRequest request =
new AlipayTradeFastpayRefundQueryRequest();
AlipayTradeFastpayRefundQueryModel model =
new AlipayTradeFastpayRefundQueryModel();
model.setOutTradeNo("ORDER_202609090001");
model.setOutRequestNo("REFUND_202609090001");
request.setBizModel(model);
AlipayTradeFastpayRefundQueryResponse response =
alipayClient.execute(request);
if (response.isSuccess()) {
// 根据查询响应中的退款信息更新本地状态。
markRefundSuccess(response);
} else {
log.warn(
"Alipay refund query failed: code={}, msg={}, subCode={}, subMsg={}, body={}",
response.getCode(),
response.getMsg(),
response.getSubCode(),
response.getSubMsg(),
response.getBody()
);
}
重试策略
退款是资金操作,重试时必须保证幂等。
可以设置有限次数的退避重试,例如:
首次失败后等待 2 秒
第二次等待 5 秒
第三次等待 15 秒
每次重试前都要先查询退款结果,并始终使用相同的 out_request_no。不要无限重试,也不要让用户通过连续点击退款按钮创建多个退款单。
本地退款状态建议至少分为:
INIT
PROCESSING
SUCCESS
FAILED
MANUAL_REVIEW
遇到 aop.ACQ.SYSTEM_ERROR 时,应先将退款状态设为 PROCESSING,不要立即标记为 FAILED。
仍无法解决时
如果问题持续存在,应整理以下信息并提交给支付宝技术支持:
- 商户账号及
app_id; - 调用接口名称
alipay.trade.refund; - 问题发生的准确时间;
- 支付宝交易号
trade_no; - 商户订单号
out_trade_no; - 退款请求号
out_request_no; - 完整的
code、msg、sub_code、sub_msg; - 脱敏后的请求参数和原始响应;
- 是否所有退款请求都失败;
- 最近是否更换过证书、密钥、SDK、网关或商户配置。
仅凭 aop.ACQ.SYSTEM_ERROR 无法确定唯一原因。排查时,应先保留原始响应、查询退款结果并保证重试幂等,再根据影响范围判断是临时服务异常,还是商户侧的配置问题。
备注:内容仅供参考。
