Skip to content

fix #95291: message tool fails to deliver files/images on Feishu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone#95514

Merged
steipete merged 5 commits into
openclaw:mainfrom
mikasa0818:feat/issue-95291
Jul 21, 2026
Merged

Conversation

@mikasa0818

@mikasa0818 mikasa0818 commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Closes #95291

What Problem This Solves

Fixes an issue where Feishu/Lark users sending local files or images through the OpenClaw message tool could see media delivery fail with CDN-edge upload errors, even though the same app credentials and media succeeded through a standalone Lark SDK upload.

Why This Change Was Made

OpenClaw intentionally wraps the Lark SDK HTTP instance to inject request timeouts. The SDK upload helpers provide multipart upload data as a plain object containing Buffer media parts; relying on implicit serialization in the wrapped transport path was fragile. This change keeps the canonical SDK upload APIs and normalizes only Feishu media upload requests into explicit native FormData before delegating to the SDK default HTTP instance.

The follow-up type repair also copies each Buffer media part into an ArrayBuffer-backed Uint8Array before constructing the native Blob. That preserves the uploaded bytes while satisfying the current TypeScript BlobPart contract, which rejects Buffer<ArrayBufferLike> because it can be backed by SharedArrayBuffer.

User Impact

Users can send Feishu message media attachments from local files/images through OpenClaw without hitting the malformed multipart upload path. The fix applies to both file and image uploads while leaving unrelated Feishu requests unchanged.

Evidence

  • Main sync completed for the PR branch before this round of validation.
  • Type checks: node scripts/run-tsgo.mjs -p tsconfig.extensions.json, node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo, node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo, and node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo — passed.
  • Current-head check-test-types follow-up: the Feishu client regression test now reads the delegated request options from the actual request mock, matching the helper's typed input and preserving the runtime assertion.
  • Focused Feishu Vitest: CI=1 node scripts/run-vitest.mjs extensions/feishu/src/client.test.ts extensions/feishu/src/media.test.ts — passed.
  • Extension package boundary compile: node scripts/check-extension-package-tsc-boundary.mjs --mode=compile — passed.
  • Extension lint: node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.extensions.json extensions — passed.
  • Tooling attribution check for the prior visible tooling failure: node scripts/run-vitest.mjs run --config test/vitest/vitest.tooling.config.ts --reporter=verbose src/scripts/test-projects.test.ts — passed after syncing current main and refreshing dependencies.
  • Whitespace check: git diff --check — passed.
  • Authorized live Feishu proof from the earlier round on this PR: standalone SDK file/image uploads succeeded; OpenClaw Feishu helper file/image uploads succeeded; OpenClaw Feishu media-send path delivered file and image messages to both a private test DM and a private test group.
  • Regression coverage: the focused client test verifies SDK-style multipart upload data with a Buffer media part is converted to explicit FormData while preserving timeout injection and headers.

Summary

  • Behavior or issue addressed: Fix Feishu/Lark message media delivery for local files and images when the SDK upload goes through OpenClaw's timeout-aware HTTP instance.
  • Why it matters / User impact: The message tool could fail before Feishu returned a normal OpenAPI JSON response, producing CDN-edge upload errors even though the same app credentials and media worked through a standalone Lark SDK upload.
  • Fix classification: Root-cause transport/request-shaping fix for Feishu SDK multipart uploads, plus a mechanical TypeScript BlobPart compatibility repair.
  • What did NOT change: This does not change Feishu public config, target routing, message schema, SDK method selection, retry policy, or any unrelated provider behavior; only the Feishu media-upload request body representation is normalized.
  • Architecture / source-of-truth check: The canonical source-of-truth remains the Lark SDK upload APIs (im.file.create and im.image.create) plus OpenClaw's existing timeout-aware HTTP wrapper. The Buffer-to-Blob conversion only adapts Node Buffer bytes to the native BlobPart type accepted by the wrapper boundary.

Root Cause

  • Root cause: The Feishu SDK generated file/image upload calls pass a plain object with a Buffer part while setting Content-Type: multipart/form-data. OpenClaw wraps the SDK default HTTP instance to inject timeouts; in that wrapped path, relying on implicit multipart serialization was fragile and caused malformed upload requests to be rejected at the Feishu CDN edge before normal OpenAPI handling. The review follow-up then exposed that passing a Node Buffer<ArrayBufferLike> directly to new Blob(...) is not accepted by current TypeScript DOM typings because the Buffer backing store may be SharedArrayBuffer.
  • Why this is root-cause fix: The patch fixes the source contract mismatch at the HTTP wrapper boundary rather than masking the send failure downstream. When a multipart request contains a Buffer file or image part, the wrapper now builds an explicit native FormData payload before delegating to the SDK default HTTP instance, so the SDK upload request has the multipart shape Feishu expects while the canonical SDK methods and timeout behavior remain unchanged. The follow-up copies the Buffer into a fresh Uint8Array<ArrayBuffer> before creating the Blob, preserving bytes while using a BlobPart that TypeScript and native Blob accept.
  • Patch quality notes: The normalization is narrowly gated on multipart requests with Feishu media Buffer parts, preserves timeout injection and headers, skips null/undefined fields, serializes only explicit scalar form fields, and preserves uploaded file names where available. The Buffer copy is local to media parts and does not change non-upload request handling.

Real behavior proof

  • Real environment tested: Authorized live Feishu self-built app and bot in private test DM and group conversations during the earlier live-proof round on this PR.
  • Exact live steps run after the multipart normalization patch: Exercised standalone SDK file/image uploads, OpenClaw Feishu helper file/image uploads, and OpenClaw Feishu media-send delivery to both a DM and a group.
  • Evidence after fix: Standalone SDK upload succeeded for a small text file and PNG image; OpenClaw helper upload succeeded for the same media classes; OpenClaw Feishu message media-send path delivered file and image messages to both DM and group.
  • Observed result after fix: All live upload/send checks completed successfully with Feishu message receipts for the DM and group deliveries; no CDN-edge multipart upload failure was observed after the fix.
  • What was not re-run in this round: The private Feishu tenant live path was not replayed for the mechanical Buffer-to-BlobPart type repair. This round revalidated the code path with focused Feishu tests plus full relevant type/lint/package-boundary checks after syncing main.

Regression Test Plan

  • node scripts/run-tsgo.mjs -p tsconfig.extensions.json — passed.
  • node scripts/run-tsgo.mjs -p tsconfig.core.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core.tsbuildinfo — passed.
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.core.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/core-test.tsbuildinfo — passed.
  • node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo — passed.
  • CI=1 node scripts/run-vitest.mjs extensions/feishu/src/client.test.ts extensions/feishu/src/media.test.ts — passed.
  • node scripts/check-extension-package-tsc-boundary.mjs --mode=compile — passed.
  • node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.extensions.json extensions — passed.
  • node scripts/run-vitest.mjs run --config test/vitest/vitest.tooling.config.ts --reporter=verbose src/scripts/test-projects.test.ts — passed.
  • git diff --check — passed.
  • Target test file: extensions/feishu/src/client.test.ts.
  • Scenario locked in: A Feishu SDK-style multipart file upload request containing a Buffer file part is passed through the timeout-aware HTTP wrapper and must be delegated as explicit FormData rather than the original plain object.
  • Why this is the smallest reliable guardrail: The regression test locks the wrapper boundary where the malformed multipart request was introduced, while existing media tests continue covering message routing and upload/send integration behavior.

Review findings addressed

  • RF-001 (status: ⏳ waiting on author): addressed by syncing main, applying the requested repair, and revalidating the PR branch. The label itself is expected to clear only after exact-head CI/bot or maintainer re-evaluation.
  • RF-002 / RF-006 (check-prod-types / extension type checks): fixed. node scripts/run-tsgo.mjs -p tsconfig.extensions.json passed after copying Buffer media parts into Uint8Array<ArrayBuffer> before new Blob(...).
  • RF-003 (live Feishu proof not independently replayed by reviewer): disclosed. The public-safe live proof from the earlier round remains applicable to the multipart normalization behavior; this mechanical type repair was not replayed against the private tenant path.
  • RF-004 / RF-005 (single mechanical repair; convert the Buffer before constructing the Blob): fixed in extensions/feishu/src/client.ts by adding a local Buffer-to-BlobPart adapter before constructing the native Blob.
  • RF-007 (extension package boundary compile): passed with node scripts/check-extension-package-tsc-boundary.mjs --mode=compile.
  • RF-008 (focused Feishu tests): passed with CI=1 node scripts/run-vitest.mjs extensions/feishu/src/client.test.ts extensions/feishu/src/media.test.ts.
  • Current-head check-test-types follow-up: fixed by passing mockBaseHttpInstance.request to the test helper that reads mock call options; node scripts/run-tsgo.mjs -p test/tsconfig/tsconfig.extensions.test.json --incremental --tsBuildInfoFile .artifacts/tsgo-cache/extensions-test.tsbuildinfo now passes.
  • RF-009 (extension lint): passed with node scripts/run-oxlint.mjs --tsconfig config/tsconfig/oxlint.extensions.json extensions.

Merge risk

  • Risk labels considered: Feishu plugin, media upload, SDK HTTP wrapper, multipart request handling, native FormData/Blob, public contract scan.
  • Risk explanation: Low-to-moderate. The change sits in a shared Feishu client wrapper, but the new behavior is narrowly gated to multipart requests that contain media Buffer parts. Non-upload requests, public config/schema, target normalization, provider routing, and timeout defaults remain unchanged. The follow-up Buffer copy is local to Blob construction and only changes the in-memory representation passed to native Blob.
  • Why acceptable: The affected path already intends to send multipart Feishu uploads, and live proof covered both upload and message delivery for file/image media through the OpenClaw path. The out-of-scope boundary is explicit: no unrelated attachment-size, retry, routing, or public API/config behavior is changed.
  • Maintainer-ready confidence: High for the reported Feishu media delivery failure; focused Feishu tests, relevant full type/lint/package-boundary checks, and authorized live Feishu proof are now all accounted for.

@openclaw-barnacle openclaw-barnacle Bot added channel: feishu Channel integration: feishu size: S labels Jun 21, 2026
@clawsweeper

clawsweeper Bot commented Jun 21, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 17, 2026, 8:53 AM ET / 12:53 UTC.

Summary
The PR converts Feishu SDK file/image upload objects containing Buffer media into native FormData before the shared HTTP wrapper delegates them, with regression coverage for timeout and header preservation.

PR surface: Source +85, Tests +34. Total +119 across 2 files.

Reproducibility: yes. at source level: current main still routes SDK-shaped Buffer multipart data through the timeout/proxy-aware wrapper without this normalization, and the linked report gives a concrete message-tool file/image path. The supplied live proof also reports the failure disappearing after the patch, although this review did not independently execute a private Feishu tenant.

Review metrics: none identified.

Root-cause cluster
Relationship: fixed_by_candidate
Canonical: #95291
Summary: This PR is the candidate fix for the linked malformed-multipart Feishu media report; the other related items concern separate credential, file-type, or streaming-card failure paths.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🦞 diamond lobster
Proof: 🦞 diamond lobster
Patch quality: 🦞 diamond lobster
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Risk before merge

  • [P1] The shared Feishu request wrapper changes multipart encoding for every SDK request containing a Buffer-valued file or image part; a serialization mistake could suppress or corrupt file/image delivery even though unrelated requests remain gated out.
  • [P1] The branch is currently behind main and exact-head CI still has pending work plus one reported changed-test failure, so maintainers should require a refreshed clean merge result and completed required checks before landing.

Maintainer options:

  1. Refresh and land the focused fix (recommended)
    Rebase or merge current main, confirm the required exact-head checks, and land the existing narrow multipart normalization if the merge result remains unchanged in behavior.
  2. Pause if multipart scope expands
    Pause for another Feishu owner review if the refreshed branch begins normalizing additional SDK multipart shapes or changes upload fields beyond file and image requests.

Next step before merge

  • No automated repair is indicated; a Feishu owner should review the refreshed merge result and land it once exact-head required checks complete.

Security
Cleared: The focused Feishu source/test change adds no dependency, workflow, permission, secret-handling, install, publishing, or third-party code-execution surface.

Review details

Best possible solution:

Land the narrowly gated wrapper-boundary normalization after refreshing against current main and confirming exact-head checks, preserving the canonical Lark SDK upload methods, timeout/proxy behavior, filenames, scalar multipart fields, and byte-for-byte media contents.

Do we have a high-confidence way to reproduce the issue?

Yes at source level: current main still routes SDK-shaped Buffer multipart data through the timeout/proxy-aware wrapper without this normalization, and the linked report gives a concrete message-tool file/image path. The supplied live proof also reports the failure disappearing after the patch, although this review did not independently execute a private Feishu tenant.

Is this the best way to solve the issue?

Yes; adapting the SDK upload payload at the wrapper boundary is narrower and more maintainable than bypassing the SDK or adding downstream fallbacks, and it leaves configuration, routing, retries, and non-upload requests unchanged.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 62407b36d780.

Label changes

Label changes:

  • add rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • remove rating: 🐚 platinum hermit: Current PR rating is rating: 🦞 diamond lobster, so this older rating label is no longer current.

Label justifications:

  • P2: The PR fixes a real but Feishu-limited file/image delivery failure with a bounded wrapper change and available workaround.
  • merge-risk: 🚨 message-delivery: The patch changes how Feishu file and image upload bodies are encoded, so an incorrect merge could cause attachments to fail, corrupt, or disappear.
  • rating: 🦞 diamond lobster: Overall readiness is 🦞 diamond lobster; proof is 🦞 diamond lobster and patch quality is 🦞 diamond lobster.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (live_output): The PR documents an authorized after-fix live Feishu run covering SDK uploads, OpenClaw helper uploads, and actual file/image delivery to both a DM and group; the later Buffer-to-BlobPart adjustment is mechanical and retains focused byte-path, type, lint, and package-boundary validation.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR documents an authorized after-fix live Feishu run covering SDK uploads, OpenClaw helper uploads, and actual file/image delivery to both a DM and group; the later Buffer-to-BlobPart adjustment is mechanical and retains focused byte-path, type, lint, and package-boundary validation.
Evidence reviewed

PR surface:

Source +85, Tests +34. Total +119 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 86 1 +85
Tests 1 34 0 +34
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 120 1 +119

What I checked:

  • Changed request boundary: The patch narrowly detects multipart SDK requests containing a Buffer-valued file or image part, constructs explicit FormData, and applies it before the existing request-option injection and SDK HTTP delegation. (extensions/feishu/src/client.ts:89, c6bc27f8e6ab)
  • Regression coverage: The added test exercises an SDK-shaped file upload and verifies that the delegated request retains the Feishu timeout and headers while replacing the plain upload object with FormData. (extensions/feishu/src/client.test.ts:328, c6bc27f8e6ab)
  • Current-main behavior: Current main contains the timeout/proxy-aware Feishu HTTP wrapper but not the branch's multipart Buffer-to-FormData normalization, so the central fix has not already been implemented. (extensions/feishu/src/client.ts:85, 62407b36d780)
  • Dependency contract: The Lark SDK uses its canonical im.file.create and im.image.create upload APIs, while Axios officially supports native FormData payloads and derives multipart encoding from the payload. (github.com)
  • Live behavior proof: The PR reports after-fix standalone SDK uploads, OpenClaw helper uploads, and OpenClaw message delivery for files and images in both a private Feishu DM and group; the existing proof gate and prior completed review accepted this evidence as sufficient. (c6bc27f8e6ab)
  • Wrapper provenance: The timeout-aware Feishu HTTP wrapper appears to date to commit ba223c7, which added the wrapper to prevent per-chat queue deadlocks; this PR adapts multipart uploads at that same owner boundary. (extensions/feishu/src/client.ts:85, ba223c7766)

Likely related people:

  • Ayane: Commit ba223c7 introduced the Feishu timeout-aware SDK HTTP wrapper that this PR changes. (role: introduced behavior; confidence: high; commits: ba223c7766; files: extensions/feishu/src/client.ts, extensions/feishu/src/client.test.ts)
  • @vincentkoc: Recent merged Feishu refactors and delivery fixes show sustained work across the channel runtime and message-delivery paths. (role: recent area contributor; confidence: medium; commits: 851de3554e, 2aa313cd90; files: extensions/feishu/src/client.ts, extensions/feishu/src/media.ts, extensions/feishu/src/reply-dispatcher.ts)
  • @m1heng: The bundled Feishu plugin lineage originated from the community plugin integration, making this person relevant for broader plugin behavior context. (role: feature introducer; confidence: medium; commits: 2267d58afc; files: extensions/feishu/src/client.ts, extensions/feishu/src/media.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-06-29T08:52:07.565Z sha b435447 :: needs maintainer review before merge. :: none

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. labels Jun 21, 2026
@NianJiuZst

Copy link
Copy Markdown
Contributor

Complementary observations on top of ClawSweeper's review:

The fix to normalize SDK multipart Buffer uploads into native FormData inside the timeout-aware HTTP wrapper is a clean change. Two observations:

  • FormData encoding decision. Modern fetch in Node 18+ supports FormData natively. Worth a code comment near the conversion explaining why this PR chose "build FormData and let the wrapper serialize" over "manually build multipart/form-data with boundary" — the former is correct, but future contributors might think the manual approach is faster.

  • File-type and content-type defaults. The diff adds 75 lines and removes 1. Without seeing the full patch, the key concern is whether the new code path properly handles:

    • File type detection (extension → mime, not just extension passthrough)
    • Empty files (0-byte Buffer)
    • Large files (>chunk threshold, where streaming matters)
    • Unicode filenames
      Each of these is a likely regression source for Feishu media. Worth explicit test coverage for each.
  • Tests are focused but may miss integration. extensions/feishu/src/client.test.ts gets 42 added lines — probably 2-3 new test cases. A unit-level test of the FormData construction is good but doesn't catch SDK-level integration issues (e.g., does the Feishu SDK actually accept the new shape?). If the project has a sandbox tenant or a recorded HTTP fixture, an integration test that round-trips through the SDK would catch this.

  • ClawSweeper noted "not independently reproducible". For a 400-error fix, the actual fix is easy to verify with a single Feishu API call. If a maintainer has a Feishu tenant, a quick before/after test (upload a small image, check 200 vs 400) would close the proof gap fast.

@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 21, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. labels Jun 29, 2026
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jul 16, 2026
@clawsweeper clawsweeper Bot added rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. labels Jul 17, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the stale Marked as stale due to inactivity label Jul 18, 2026
@steipete steipete self-assigned this Jul 21, 2026
mikasa0818 and others added 5 commits July 20, 2026 22:53
Convert Feishu SDK multipart Buffer upload parts into explicit FormData
before they reach the wrapped HTTP transport. The SDK upload helpers
pass multipart data as a plain object with Buffer media parts; relying on
implicit serialization in the timeout/proxy-aware HTTP wrapper was fragile
and caused file/image delivery failures (400 volc-dcdn / write ECONNRESET)
even though the same credentials succeeded via a standalone SDK upload.

Adds normalizeMultipartUploadData, applied on the request path of the
shared Feishu HTTP instance, plus a regression test covering the
multipart-to-FormData normalization.

Rebased onto current origin/main, which replaced the old synchronous
injectTimeout path with the async proxy-aware injectRequestOptions flow;
the multipart normalization is now applied before that flow.
@clawsweeper

clawsweeper Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper status: review started.

I am starting a fresh review of this pull request: fix #95291: message tool fails to deliver files/images on Feishu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone This is item 1/1 in the current shard. Shard 0/1.

This placeholder means the worker is alive and reading the current context. I will edit this same comment with the actual review when the claws are done clicking.

Crustacean status: shell secured, claws on keyboard, evidence pebbles being sorted.

@steipete
steipete merged commit 644645f into openclaw:main Jul 21, 2026
88 checks passed
@steipete

Copy link
Copy Markdown
Contributor

Merged via squash.

vincentkoc added a commit that referenced this pull request Jul 21, 2026
* origin/main: (24 commits)
  fix(agents): keep compaction on live session model (#95713)
  fix(plugin-sdk): guard provider catalog live URL parsing against malformed responses (#109986)
  chore(cli): drop dead classifiers and single-use wrappers left by fallback removal (#112191)
  feat(ui): expand the lobster pet's random universe (#112073)
  chore(ci): audit dependency fingerprint exports (#112190)
  fix(ui): preserve graphemes in provider icons (#109509)
  fix(ui): align settings search with navigation rows (#112172)
  fix(agents): allow configless gateway rebind to activate standalone owner (#111841)
  fix(secrets): register secret targets for installed-origin plugins (#104347)
  improve(ui): show real machine identity in the place picker (#112162)
  fix: webChat scrollback history is too limited — older assistant replies and tool outputs disappear when scrolling… (#104250)
  test(ui): run DOM-free suites in Node (#112031)
  feat(nodes): make computer.act eligibility capability-based for desktop nodes (#112107)
  fix(apps): harden mobile gateway and watch state
  fix(ci): restore Z.AI API Platform validation (#112171)
  fix(ui): prevent Logs controls from overlapping (#112170)
  fix #95291: message tool fails to deliver files/images on Feishu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone (#95514)
  refactor(cli)!: remove automatic gateway→embedded fallback from openclaw agent (#112074)
  refactor: move provider transports into packages/ai behind a typed host port (#111669)
  fix(anthropic): complete transcript reverse-scan windows across short reads (#109431)
  ...
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request Jul 22, 2026
…shu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone (openclaw#95514)

* fix(feishu): normalize media upload multipart data

Convert Feishu SDK multipart Buffer upload parts into explicit FormData
before they reach the wrapped HTTP transport. The SDK upload helpers
pass multipart data as a plain object with Buffer media parts; relying on
implicit serialization in the timeout/proxy-aware HTTP wrapper was fragile
and caused file/image delivery failures (400 volc-dcdn / write ECONNRESET)
even though the same credentials succeeded via a standalone SDK upload.

Adds normalizeMultipartUploadData, applied on the request path of the
shared Feishu HTTP instance, plus a regression test covering the
multipart-to-FormData normalization.

Rebased onto current origin/main, which replaced the old synchronous
injectTimeout path with the async proxy-aware injectRequestOptions flow;
the multipart normalization is now applied before that flow.

* fix(feishu): scope multipart media normalization

* test(feishu): mark multipart auth fixture synthetic

* test(feishu): use field-shaped secret fixtures

* fix(feishu): validate multipart upload endpoints

---------

Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

channel: feishu Channel integration: feishu merge-risk: 🚨 message-delivery 🚨 May drop, duplicate, misroute, suppress, or wrongly target messages. P2 Normal backlog priority with limited blast radius. proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🦞 diamond lobster Very strong PR readiness with only minor maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

message tool fails to deliver files/images on Feishu (400 volc-dcdn / write ECONNRESET) while same Lark SDK upload succeeds standalone

3 participants