I-040 — Internal transfer rejected: UTC date sent to a Hong Kong bank¶
✅ Attestation: read AGENTS.md · board checked by scope (no open T/I covers the OCBC IFT path) · ticket-only fix (a date helper + two call sites). Source: Bank Access (Diagnosticcs) · https://claude.ai/code/session_01S4ztAsDZfR97qXjhPdwLn4
Symptom¶
Owner (2026-08-31): transferring HKD 283 from savings to checking on the Bank Access page returns
"OCBC API Error [900001]: System Error". Five attempts, all refused. 900001 is OCBC's generic
catch-all — passed straight through by velocity-client.ts — and carries no detail.
Root cause (from the owner's production log export)¶
Every attempt ran between 16:03 and 16:16 UTC on 2026-08-31 — which is 00:03–00:16 on 2026-09-01 in Hong Kong. The encrypted payload logged at the time:
The app sent valueDate = 2026-08-31 while Hong Kong was already on 2026-09-01 — a value date
in the past, which a bank will not accept.
new Date().toISOString().split('T')[0] yields the UTC date. Vercel's runtime is UTC and Hong
Kong is UTC+8, so for eight hours of every day (16:00–24:00 UTC) the date is a full day behind
Hong Kong. This OCBC entity is explicitly the Hong Kong one (iftType: 'IFT_HK',
beneficiaryAccountEntity: 'HK'). Any transfer attempted after midnight Hong Kong time was
back-dated and rejected — which is precisely when the owner tried.
Two places had the same defect, both fixed:
- velocity-client.ts:1250 — the valueDate default on submitInternalTransfer (the payload)
- velocity-client.ts:152 — the x-source-date-time request header sent on every OCBC call
Ruled out along the way: the account-number format (the owner tried 802757699051,
757699051, and 802-757699-051; all three normalise to the same 9 digits, and all three failed
identically), and the T-205 Airwallex gate (it matches only /api/airwallex/; the OCBC route
returns 401, not 403).
Fix¶
lib/ocbc/hongKongDate.ts — hongKongToday(), using Intl with the explicit IANA zone
Asia/Hong_Kong rather than a hard-coded +8 offset. Used for both the value date and the request
header. Six tests pin the behaviour, including a direct reproduction of the failing moment
(16:03 UTC → 2026-09-01) and the 16:00 UTC rollover boundary.
Not proven, and worth knowing¶
900001 is generic, so this fix cannot be proven to be the whole story without a successful
transfer. The back-dating is a real defect regardless. Cheap confirmation: retry during Hong Kong
business hours, when the UTC and Hong Kong dates agree and the bug is dormant — if it succeeds
then, the diagnosis holds.
Related finding (not fixed here)¶
The working-day/value-date lookup that should supply the correct date is itself broken and its failure is swallowed:
/calendar-bv/api/hk/v1/calendar/evaluation/work-day/ITSO?debitCurrencyCode=HKD&trxnCurrencyCode=HKD
→ OCBC API Error [CAL-50004]: No Calendar Group Match
[velocity/payment-init] Calendar check failed (non-critical)
So the app never learns OCBC's own next valid value date and falls back to "today". Worth fixing so transfers outside banking hours are dated forward to the next working day rather than to a date OCBC may reject. Left out of this ticket deliberately — it needs the correct calendar parameters, which means observing what the OCBC portal itself sends.
Also flagged: velocity-e2ee logs the value-date/account/amount plaintext to production logs.
Invaluable here — it is what made this diagnosis possible — but it should be masked once the IFT
path is confirmed working.
Log¶
- 2026-08-31 — Diagnosed from the owner's Vercel log export; fixed both UTC-date usages. Source: Bank Access (Diagnosticcs) · https://claude.ai/code/session_01S4ztAsDZfR97qXjhPdwLn4