Repository navigation
EscrowDisputeController.raiseDispute() always throws: RaiseDisputeSchema requires escrowId/signerAddress the body never sends #800
Description
Description
POST /escrows/:id/dispute (EscrowDisputeController.raiseDispute() in backend/src/dispute/escrow-dispute.controller.ts, lines 95-108) validates the request body against RaiseDisputeSchema, but the schema requires two fields that this endpoint's documented body never contains, so every call to this route fails validation.
RaiseDisputeSchema (backend/src/escrow/escrow.dto.ts, lines 28-33):
export const RaiseDisputeSchema = z.object({
escrowId: z.string().min(1),
reason: z.string().min(10).max(500),
evidenceUrl: z.string().url().optional(),
signerAddress: z.string().regex(STELLAR_ADDRESS_REGEX),
});escrowId and signerAddress are both required (no .optional()). The controller call site:
async raiseDispute(
@Param('id') id: string,
@Body() dto: RaiseDisputeDto,
@Req() req: AuthenticatedRequest,
) {
const { reason } = RaiseDisputeSchema.parse(dto ?? {});
...But the route's own @ApiBody schema (lines 63-75) documents only a reason property with no required array, and the method's own @ApiOperation description says "The authenticated wallet must be the escrow's depositor or beneficiary; it is recorded as the initiator" — i.e. escrowId is meant to come from the :id path param (already available as id) and the signer is meant to come from the authenticated JWT (req.user.address), not from the request body at all. Every real client following the documented contract sends { "reason": "..." } with no escrowId/signerAddress, which RaiseDisputeSchema.parse() rejects with a ZodError (surfaced as an HTTP 400 by the global SentryExceptionFilter/Zod handling) before the saga is ever invoked.
This is independently confirmed by the controller's own spec file never compiling against the real method signature. backend/src/dispute/escrow-dispute.controller.spec.ts calls controller.raiseDispute('esc-001', { reason: 'Not delivered' }, req(address)) (lines 87, 97, 104, 115, 124, 141, 145) — a body with only reason, matching the documented API contract, not the DTO type RaiseDisputeDto that RaiseDisputeSchema produces ({ escrowId: string; reason: string; signerAddress: string; evidenceUrl?: string }). Running it:
$ npx jest src/dispute/escrow-dispute.controller.spec.ts
FAIL src/dispute/escrow-dispute.controller.spec.ts
● Test suite failed to run
src/dispute/escrow-dispute.controller.spec.ts:87:58 - error TS2345: Argument of type '{ reason: string; }' is not assignable to parameter of type '{ escrowId: string; reason: string; signerAddress: string; evidenceUrl?: string | undefined; }'.
Type '{ reason: string; }' is missing the following properties from type '{ escrowId: string; reason: string; signerAddress: string; evidenceUrl?: string | undefined; }': escrowId, signerAddress
(and six more identical errors at lines 97, 104, 115, 124, 141, 145). The entire spec file fails to compile, so none of its assertions — authorization checks, notification dispatch, duplicate-dispute rejection — currently run, and at runtime every real POST /escrows/:id/dispute call with the documented body throws instead of raising a dispute.
Component
Backend
Difficulty
🟡 Medium
Tasks
- Change
EscrowDisputeController.raiseDispute()to validate only the fields this route actually expects in the body (reason, optionallyevidenceUrl) — e.g. introduce a narrower schema/DTO for this route, or makeescrowId/signerAddressoptional onRaiseDisputeSchemaand ignore them here since they come from the path param and JWT respectively - Update
escrow-dispute.controller.spec.tsif the DTO type changes so it still type-checks against the real signature - Verify
RaiseDisputeSchemais not needed elsewhere with its current required shape before narrowing it (currently it has exactly one call site)
Acceptance Criteria
-
POST /escrows/:id/disputewith body{ "reason": "<10+ chars>" }and a valid JWT succeeds and opens a dispute saga, matching the documented API contract -
npx jest src/dispute/escrow-dispute.controller.spec.tscompiles and its tests run (pass or fail on their own merits)
Estimated Time
1 hour
Activity
Abayomi-fx commentedon Oct 22, 2026
@Abayomi-fx has applied to work on this issue as part of the Stellar Wave Program's 10th wave.
ℹ️ Repo Maintainers: To accept this application, review their application or assign @Abayomi-fx to this issue.
BashBurna26 commentedon Oct 22, 2026
@BashBurna26 has applied to work on this issue as part of the Stellar Wave Program's 10th wave.
ℹ️ Repo Maintainers: To accept this application, review their application or assign @BashBurna26 to this issue.
Ayfataan commentedon Oct 22, 2026
@Ayfataan has applied to work on this issue as part of the Stellar Wave Program's 10th wave.
ℹ️ Repo Maintainers: To accept this application, review their application or assign @Ayfataan to this issue.
dev-debbie-umoh commentedon Oct 22, 2026
@dev-debbie-umoh has applied to work on this issue as part of the Stellar Wave Program's 10th wave.
ℹ️ Repo Maintainers: To accept this application, review their application or assign @dev-debbie-umoh to this issue.
dev-susa commentedon Oct 22, 2026
@dev-susa has applied to work on this issue as part of the Stellar Wave Program's 10th wave.
ℹ️ Repo Maintainers: To accept this application, review their application or assign @dev-susa to this issue.
drips-wave commentedon Oct 22, 2026
Congratulations, @dev-susa! 🎉 Your application was accepted by the repo's maintainers, and the issue is due on October 22, 2026.
🧑💻 @dev-susa: Please resolve the issue such that the repo's maintainers have enough time to review your contribution before the due date. You'll earn Points for completing the issue on-time, which will make you eligible for a share of the Stellar Wave Program's reward pool.
Warning
When opening a PR, please link it to this issue to ensure it gets tracked accurately. Points are awarded when this issue is marked as completed by the maintainer.
🤠 Repo maintainers: Please keep an eye on the contributor's progress and review their work before the due date. You can manage this issue, including adjusting its complexity and points, here.
🌊 Happy Wave 🌊
fix(dispute): make reason optional on POST /escrows/:id/dispute (Refs t…
fix(dispute): accept the documented dispute body on POST /escrows/:id…
fix(dispute): make reason optional on POST /escrows/:id/dispute (Refs t…
fix(backend): dispute body, provider latency, dedup cap and k6 routes (…
grantfox-oss commentedon Oct 24, 2026
🎉 This issue has been marked as completed on GrantFox!
@dev-susa's PR #842 was approved and merged by @meshackyaro.
🏆 @dev-susa: You earned 35 FoxPoints for this contribution! Your current tier: Explorer (481 total points). Track your full progress on GrantFox.
👏 Great work, @dev-susa! Keep contributing to trustflow-protocol.
drips-wave commentedon Oct 24, 2026
This issue has been completed by @dev-susa as part of the Stellar Wave Program's 10th Wave 🥳
😎 @dev-susa: You earned 200 Points for completing this issue! Once the Wave's rewards are finalized, you'll be eligible for a percentage of the Wave's reward pool based on the percentage of total points you've earned. Learn more here. You can also Leave a review to share your experience working on this issue.
🧑💻 Repo maintainers: How'd the contributor do? Leave a review to share your experience working with them.