{"record":{"id":"a80ceb0732e498e1","repo":"yudaocode/SpringBoot-Labs","slug":"error-a80ceb","errorCode":null,"errorMessage":"扣除余额失败","messagePattern":"扣除余额失败","errorType":"http","errorClass":"java.lang.RuntimeException","httpStatus":500,"severity":"error","filePath":"lab-52/lab-52-seata-at-httpclient-demo/lab-52-seata-at-httpclient-demo-order-service/src/main/java/cn/iocoder/springboot/lab52/orderservice/service/OrderServiceImpl.java","lineNumber":72,"sourceCode":"                params, HttpResponse.class);\n        // 解析结果\n        Boolean success = Boolean.valueOf(EntityUtils.toString(response.getEntity()));\n        if (!success) {\n            throw new RuntimeException(\"扣除库存失败\");\n        }\n    }\n\n    private void reduceBalance(Long userId, Integer price) throws IOException {\n        // 参数拼接\n        JSONObject params = new JSONObject().fluentPut(\"userId\", String.valueOf(userId))\n                .fluentPut(\"price\", String.valueOf(price));\n        // 执行调用\n        HttpResponse response = DefaultHttpExecutor.getInstance().executePost(\"http://127.0.0.1:8083\", \"/account/reduce-balance\",\n                params, HttpResponse.class);\n        // 解析结果\n        Boolean success = Boolean.valueOf(EntityUtils.toString(response.getEntity()));\n        if (!success) {\n            throw new RuntimeException(\"扣除余额失败\");\n        }\n    }\n\n}\n","sourceCodeStart":54,"sourceCodeEnd":77,"githubUrl":"https://github.com/yudaocode/SpringBoot-Labs/blob/6c12efaed06d12907a0f40dd2ad1f7020aec8798/lab-52/lab-52-seata-at-httpclient-demo/lab-52-seata-at-httpclient-demo-order-service/src/main/java/cn/iocoder/springboot/lab52/orderservice/service/OrderServiceImpl.java#L54-L77","documentation":"Mirror of error 18: the order service calls the account service at http://127.0.0.1:8083/account/reduce-balance via Seata's DefaultHttpExecutor and throws RuntimeException('扣除余额失败') when the response body isn't true. The XID-propagating HTTP call makes the deduction a branch of the global transaction; the throw rolls the whole purchase back (order insert + stock deduction).","triggerScenarios":"Order creation when the account service returns false — i.e., its reduce-balance failed with insufficient balance (errors 14/15). Requires account service on 127.0.0.1:8083 and the Seata infrastructure running.","commonSituations":"End-to-end rollback demo: once a test user's balance is drained, every subsequent order fails here, and observers should confirm the previously deducted stock and created order get rolled back. Pitfalls: wrong port (8083) or service not started; account service returning an error page (non-'true' body); missing XID propagation so the account deduction commits independently.","solutions":["Top up the test user's balance (or lower the order price) so reduce-balance succeeds.","Ensure the account service (8083) and Seata server are running before creating orders.","Confirm both /product and /account services join the same XID (check RootContext.getXID() logs on each service) so rollback spans them.","Include the remote body/status in the thrown message to speed up diagnosis."],"exampleFix":"// before\nif (!success) {\n    throw new RuntimeException(\"扣除余额失败\");\n}\n\n// after\nif (!success) {\n    throw new RuntimeException(\"扣除余额失败: userId=\" + userId + \", price=\" + price);\n}","handlingStrategy":"try-catch","validationCode":"// Pre-flight: confirm sufficient balance before creating the order:\nInteger balance = accountClient.getBalance(userId);\nif (balance == null || balance < price) {\n    throw new OrderRejectedException(\"INSUFFICIENT_BALANCE\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    reduceBalance(userId, price);\n} catch (RuntimeException e) {\n    logger.warn(\"balance branch failed: {}\", e.getMessage());\n    throw new OrderFailedException(\"BALANCE_FAILED\", e);\n}","preventionTips":["Top up test users' balance before order storms; drained users deterministically fail here.","Verify account service port 8083 and Seata server are up.","Confirm all participants log the same XID so rollback spans services."],"tags":["seata","httpclient","xid-propagation","distributed-transaction","remote-call"],"backgroundTag":null,"analyzedSha":"6c12efaed06d12907a0f40dd2ad1f7020aec8798","analyzedAt":"2026-08-14T13:06:31.500Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}