fix(line): canonicalize lowercased LINE chat ids at send boundary (#81628)#81670
fix(line): canonicalize lowercased LINE chat ids at send boundary (#81628)#81670SymbolStar wants to merge 1 commit into
Conversation
LINE userId/groupId/roomId are case-sensitive (per spec: capital U/C/R followed by 32 lowercase hex chars). The push API returns HTTP 400 when the leading letter is lowercased. Some core paths surface a lowercased recipient at the channel-owned delivery boundary: - src/routing/session-key.ts lowercases peer ids when composing agent session keys. - src/agents/tools/cron-tool.ts inferDeliveryFromSessionKey() parses that lowercased fragment and assigns it to delivery.to when there is no current delivery context, which is the path used by long-running jobs whose reply token has expired. - src/infra/outbound/delivery-queue-recovery.ts replays the stored params.to verbatim, so once a lowercased id is queued every retry reproduces the same 400. Per the codex review on openclaw#81628, fix this at the channel-owned boundary rather than spreading channel knowledge into core: extend extensions/line/src/normalizeTarget() so that whenever the stripped recipient matches the LINE chat-id shape (^[curCUR][0-9a-f]{32}$) we restore the leading letter to its canonical uppercase form. Non-id shaped strings (custom test fixtures, future formats) pass through unchanged. Adds three regression cases in extensions/line/src/send.test.ts covering: lowercase chat-id input, durable replay with line:user: prefix kept, and the existing pass-through behaviour for non-id recipients. Fixes openclaw#81628
|
Thanks for the context here. I swept through the related work, and this is now duplicate or superseded. Close: the same LINE lowercased-recipient bug was fixed by the merged replacement PR, and current main now has the LINE send guard, cron delivery-context path, and regression coverage. The only meaningful leftover in this branch is the alternate auto-uppercase strategy, which is superseded by the mainline preserve-or-fail-permanently behavior. Canonical path: Keep the merged replacement behavior on main and close this alternate branch; future cleanup should continue toward explicit delivery-context persistence rather than auto-canonicalizing invalid LINE targets. So I’m closing this here because the remaining work is already tracked in the canonical issue. Review detailsBest possible solution: Keep the merged replacement behavior on main and close this alternate branch; future cleanup should continue toward explicit delivery-context persistence rather than auto-canonicalizing invalid LINE targets. Do we have a high-confidence way to reproduce the issue? No against current main: the original source-visible path is covered by the merged replacement and later delivery-context code, and current tests cover lowercased LINE group, DM, per-peer, and send-boundary cases. The pre-fix failure was source-reproducible from session-key lowercasing and cron fallback, but that is no longer the current-main behavior. Is this the best way to solve the issue? No for this PR as the merge path: the replacement PR is the narrower maintained solution because it preserves case-exact stored delivery context and fails unrecoverable lowercased LINE-shaped recipients as permanent errors. Auto-uppercasing at the send boundary is now a superseded alternative. Security review: Security review cleared: The PR diff only changes LINE target normalization and tests; it does not add dependencies, CI changes, secrets handling, install scripts, or other supply-chain surfaces. What I checked:
Likely related people:
Codex review notes: model gpt-5.5, reasoning high; reviewed against 16e5d6692dcc; fix evidence: commit 8338412b547f, main fix timestamp 2026-05-15T16:22:59Z. |
Summary
Fixes #81628. LINE delivery silently dropped messages because
delivery.tocould reach the LINE plugin lowercased (e.g.cxxx…instead ofCxxx…); the LINE Messaging API rejects those ids withHTTP 400 The property, 'to', in the request body is invalid. Per the codex review on the issue, the fix lives at the channel-owned delivery boundary rather than in core.Root cause
LINE chat IDs (
userId/groupId/roomId) are case-sensitive (per spec: capitalU/C/Rfollowed by 32 lowercase hex chars). Several core paths can surface a lowercased value:src/routing/session-key.tslowercases peer ids when building agent session keys (buildAgentPeerSessionKey→normalizeLowercaseStringOrEmpty).src/agents/tools/cron-tool.tsinferDeliveryFromSessionKey()parses that lowercased fragment and assigns it directly todelivery.towhen there is no current delivery context — exactly the path used by long-running jobs whose reply token has expired.src/infra/outbound/delivery-queue-recovery.tsbuildRecoveryDeliverParamsreplays the storedparams.toverbatim, so once a lowercased id is queued every retry hits the same 400 until the entry is moved tofailed/.The reply-token-bound path inside the inbound webhook keeps the original casing, which is why fast replies look fine and only post-token-expiry / long task pushes fail — matching the bug report.
Fix
Extend
normalizeTarget()inextensions/line/src/send.ts(the function every push / reply / loading-animation call already routes through):line:(group|room|user):/line:prefixes (unchanged).^[curCUR][0-9a-f]{32}$, restore the leading letter to its canonical uppercase. Non-id-shaped strings (custom test fixtures, future formats) pass through unchanged.This is intentionally a single channel-owned guard so we do not have to teach core about LINE casing, and so it also covers durable-recovery replays where the queued
tois whatever core enqueued.Tests
extensions/line/src/send.test.tsadds three regression cases:line:user:u<hex>is stripped and uppercased before reachingclient.pushMessage.U-quick) still pass through unchanged so existing fixtures keep working.Risk / scope
extensions/line/src/send.ts+ its test).tois now always canonical.Verification done locally
git diff --statconfirms only the two files changed.TOOLS.mdconstraint), so the relevant suites listed in the codex review (extensions/line/src/send.test.ts,extensions/line/src/channel.sendPayload.test.ts,extensions/line/src/bot-message-context.test.ts,extensions/line/src/monitor-durable.test.ts,extensions/line/src/auto-reply-delivery.test.ts,src/agents/tools/cron-tool.test.ts,src/infra/outbound/delivery-queue.recovery.test.ts,src/infra/outbound/deliver.test.ts) are validated via CI.Fixes #81628