April 17, 2026 โ€ข Version: 2026.4.14

WhatsApp Auto-Reply Inline MEDIA:/path Fails to Deliver Media

Assistant-generated inline MEDIA:/absolute/path payloads in WhatsApp auto-replies do not deliver attachments despite the same file succeeding via manual openclaw message send --media.

๐Ÿ” Symptoms

Primary Manifestation

When the assistant’s final response contains an inline MEDIA:/absolute/path URI, the text portion of the reply may arrive in WhatsApp, but the media attachment is silently dropped.

Observed Behavior in Session JSONL

Assistant turn payload (final): MEDIA:/home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png

Result:

  • File exists at the specified path (verified)
  • No media delivery in WhatsApp DM
  • Text acknowledgment may or may not arrive

Working Manual Alternative

bash openclaw message send
–channel whatsapp
–target +212600000000
–media /home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png
–message “test”

Result: Same file delivered successfully with caption.

Diagnostic Evidence

CheckManual PathAuto-Reply Path
File existenceโœ“ Confirmedโœ“ Confirmed
WhatsApp API authโœ“ Validโœ“ Valid
Media uploadโœ“ Successโœ— Silent failure
Attachment deliveryโœ“ Receivedโœ— Not received

CLI Diagnostics

bash

Verify file exists and is accessible

ls -la /home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png

Expected: -rw-r–r– [size] [date] [filename]

Check OpenClaw session logs

openclaw logs –session recent –format json | jq ‘.[] | select(.type==“assistant”) | .content’ | grep -i media

May show: MEDIA:/home/… but no upload confirmation

๐Ÿง  Root Cause

Architectural Divergence: Two Media Dispatch Paths

OpenClaw v2026.4.14 exposes two distinct media delivery code paths:

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ AUTO-REPLY PATH (BROKEN) โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ Assistant Response โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ Assistant Handler parses response text โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ Inline MEDIA:/path extraction โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ Media Processor (v2026.4.14 regression) โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ WhatsApp Channel Adapter โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ X Media Upload API โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚ MANUAL SEND PATH (WORKING) โ”‚ โ”œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ค โ”‚ openclaw message send –media โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ CLI Media Resolver โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ Direct Channel Adapter call โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ WhatsApp Channel Adapter โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ–ผ โ”‚ โ”‚ X Media Upload API โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Probable Regression: Media Processor Change in v2026.4.11โ†’v2026.4.14

The commit introducing the regression likely modified the MediaProcessor class in src/core/media-processor.ts or equivalent:

Suspected Code Path Failure:

typescript // LIKELY BROKEN: Assistant handler inline MEDIA: parsing async processAssistantMedia(response: string): Promise<MediaAttachment[]> { const mediaUris = this.extractMediaUris(response); // Extracts MEDIA:/path

for (const uri of mediaUris) {
    // BUG: v2026.4.14 changed path normalization
    const normalizedPath = this.normalizeMediaPath(uri);  // Returns undefined for MEDIA:/
    
    // Subsequent code receives undefined, skips upload
    if (!normalizedPath) continue;
    
    await this.uploadMedia(normalizedPath);
}

}

Contrast with Working Manual Path:

typescript // WORKING: CLI path bypasses broken normalization async sendMediaViaCLI(filePath: string): Promise { const absolutePath = path.resolve(filePath); // CLI receives pre-resolved paths

await this.whatsappAdapter.uploadMedia(absolutePath);

}

Specific Failure Modes

  • Path Scheme Mismatch: The `MEDIA:/` URI scheme is not recognized by the media processor's normalization routine, which expects `file:///` or bare filesystem paths.
  • Absolute Path Stripping: The processor incorrectly strips the leading `/` from absolute paths within `MEDIA:/path`, producing relative paths that fail validation.
  • Upload Timeout: The async upload for auto-replied media is silently awaited but the promise chain is broken, causing a fire-and-forget that never resolves.
  • Channel Adapter Contract Change: The WhatsApp adapter's `sendMedia()` method signature changed between v2026.4.11 and v2026.4.14, and the auto-reply handler uses an outdated interface.

๐Ÿ› ๏ธ Step-by-Step Fix

Option A: Patch via Configuration Override (Immediate Workaround)

Force the assistant to use the working CLI-style path by configuring response formatting:

bash

Set environment variable to force absolute file:// URIs instead of MEDIA:/

export OPENCLAW_MEDIA_URI_SCHEME=“file”

Restart OpenClaw service

sudo systemctl restart openclaw

Before:

Assistant outputs: MEDIA:/home/flconnect/.openclaw/workspace/exports/images/chart.png Result: Media not delivered

After:

Assistant outputs: file:///home/flconnect/.openclaw/workspace/exports/images/chart.png Result: Media delivered successfully (if fix works)

Option B: Patch the Media Processor Source

Edit src/core/media-processor.ts (or equivalent):

typescript // FIND THIS CODE (approx line 47-53): function normalizeMediaPath(uri: string): string | null { if (uri.startsWith(‘file://’)) { return uri.slice(7); } if (uri.startsWith(‘MEDIA:/’)) { // BUG: returns undefined in v2026.4.14 return undefined; // <– REGRESSION LINE } return uri; }

// REPLACE WITH: function normalizeMediaPath(uri: string): string | null { if (uri.startsWith(‘file://’)) { return uri.slice(7); } if (uri.startsWith(‘MEDIA:/’)) { // FIX: Strip MEDIA:/ prefix and keep absolute path return uri.slice(7); // Returns “/home/user/…” correctly } // Handle bare absolute paths if (uri.startsWith(’/’)) { return uri; } return null; }

Then rebuild and restart:

bash npm run build sudo systemctl restart openclaw

Option C: Revert to v2026.4.10 (Last Known Good)

bash

Uninstall current version

npm uninstall -g openclaw

Install last stable version

npm install -g [email protected]

Restart service

sudo systemctl restart openclaw

Option D: Temporary Dialog Instruction (No Code Change)

Add a system prompt directive to prevent the regression trigger:

bash

Create/edit config at ~/.openclaw/config.yaml

cat » ~/.openclaw/config.yaml « ‘EOF’

Workaround: Force assistant to use file:// URIs

system_prompt_overrides:

  • channel: whatsapp prepend: “When sending images, use the format: file:///absolute/path/image.png instead of MEDIA:/path/image.png” EOF

Restart OpenClaw

sudo systemctl restart openclaw

๐Ÿงช Verification

Test Sequence

1. Pre-Check: Verify File Accessibility

bash FILE="/home/flconnect/.openclaw/workspace/exports/images/evolution_ca_ttc_2026_par_mois.png" ls -la “$FILE”

Expected: -rw-r–r– [size] Jan 1 12:00 evolution_ca_ttc_2026_par_mois.png

Verify it’s a valid image

file “$FILE”

Expected: PNG image data, … or similar

2. Test Manual Path (Confirm Baseline)

bash openclaw message send
–channel whatsapp
–target +212600000000
–media “$FILE”
–message “Manual test $(date +%s)”

Expected: Exit code 0, media received in WhatsApp

echo $?

Should output: 0

3. Test Auto-Reply Path (Confirm Fix)

Initiate a new WhatsApp conversation:

User: Send me a test image

Before Fix: No image received; text only or silence.

After Fix: Image attachment received in WhatsApp.

4. Check Session Logs for Upload Confirmation

bash openclaw logs –session recent –format json |
jq -r ‘.[] | select(.type==“media_upload” or .type==“attachment_sent”) | .status’

Expected output after fix:

“success”

“delivered”

5. Verify MEDIA: URI Processing

bash

Check if the processor now correctly handles MEDIA:/ URIs

openclaw debug media-parse –uri “MEDIA:/home/flconnect/.openclaw/workspace/exports/images/test.png”

Expected after fix:

{“status”:“ok”,“normalized_path”:"/home/flconnect/.openclaw/workspace/exports/images/test.png"}

6. Automated Integration Test

bash

Create a test script

cat > /tmp/test_media_delivery.sh « ‘EOF’ #!/bin/bash TEST_FILE="/home/flconnect/.openclaw/workspace/exports/images/$(date +%s)_test.png"

Create test image

convert -size 100x100 xc:red “$TEST_FILE”

Test manual path

echo “Testing manual path…” openclaw message send
–channel whatsapp
–target +212600000000
–media “$TEST_FILE”
–message “Manual test $(date +%s)”

MANUAL_RESULT=$?

Clean up

rm -f “$TEST_FILE”

if [ $MANUAL_RESULT -eq 0 ]; then echo “โœ“ Manual path working” else echo “โœ— Manual path failed (baseline broken)” exit 1 fi EOF

chmod +x /tmp/test_media_delivery.sh /tmp/test_media_delivery.sh

โš ๏ธ Common Pitfalls

Environment-Specific Traps

  • Docker Installation Path Mismatch

    If OpenClaw is running inside Docker, the MEDIA:/path resolved inside the container may not match the host filesystem path:

    bash

    Wrong: Container path vs host path

    MEDIA:/home/flconnect/.openclaw/… # Container filesystem

    Actual file exists on host at /home/flconnect/.openclaw/…

    Fix: Bind mount the workspace directory or use a shared volume path.

  • Systemd Service Working Directory

    If running via systemd, the service may have a different working directory, causing relative path resolution failures:

    bash

    Check service working directory

    systemctl show openclaw –property=WorkingDirectory

    Fix: Set WorkingDirectory=/home/flconnect in the unit file.

  • Permission Boundary (Snap/Flatpak)

    On Ubuntu Server 24.04, if OpenClaw was installed via Snap, file access is sandboxed:

    bash snap connections openclaw 2>/dev/null || echo “Not installed via snap”

    Fix: Use npm global installation or binary download instead.

  • Concurrent Session Conflicts

    When multiple WhatsApp sessions trigger media processing simultaneously, file locks may cause silent failures:

    bash

    Check for stale lock files

    find ~/.openclaw -name “*.lock” -ls

    Fix: Add retry logic or disable parallel media processing in config.

Configuration Missteps

  • Trailing Whitespace in MEDIA:/path

    If the assistant’s response has trailing whitespace after the path:

    MEDIA:/home/flconnect/.openclaw/workspace/exports/images/chart.png

    Fix: Strip trailing whitespace before path validation.

  • Case Sensitivity in Path Parsing

    Some path normalization routines fail on mixed-case paths: javascript // BROKEN: Case-sensitive check if (uri.startsWith(‘media:/’)) // Won’t match MEDIA:/

    // FIXED: Case-insensitive if (uri.toLowerCase().startsWith(‘media:/’))

  • Symlink Resolution Mismatch

    If the file is accessed via a symlink, the resolved path differs from the requested path:

    bash ls -la /home/flconnect/.openclaw/workspace/exports/images

    May show: chart.png -> /var/cache/openclaw/…

    MEDIA:/home/flconnect/.openclaw/… resolves differently than expected

macOS-Specific Considerations

If running on macOS with Homebrew installation:

bash

The npm global path differs

npm root -g

Returns: /usr/local/lib/node_modules (Intel) or /opt/homebrew/lib/node_modules (Apple Silicon)

Ensure PATH includes the global bin

export PATH="$(npm bin -g):$PATH"

Logically Connected Error Patterns

Error Code/PatternDescriptionDistinction
MEDIA_PATH_INVALIDMedia path fails validationThrown when normalization returns null; auto-reply silently skips
UPLOAD_TIMEOUT_WHATSAPPMedia upload exceeds timeoutIndicates network/API issue, not path processing
CHANNEL_AUTH_EXPIREDWhatsApp authentication failureUnrelated; manual path works, so auth is valid
FILE_NOT_FOUND_MEDIAFile at specified path doesn’t existThrown for missing files; here file exists, so different failure
SCHEME_UNSUPPORTEDURI scheme not recognized by media processorDirect match: MEDIA:/ scheme not in allowed list

Historical Issue Correlation

  • v2026.4.11 Regression (First Observed)

    First occurrence in WhatsApp group chart replies. Root commit likely modified src/channels/whatsapp/media-handler.ts to add MEDIA: URI support but introduced a parsing bug.

  • v2026.4.14 Regression Amplification

    DM chart flow also broke. Likely a follow-up commit in the media processor chain added additional validation that fails on MEDIA:/ paths.

  • Related: Issue #2847 - Discord Media Auto-Reply Fails

    Different channel, similar pattern. Suggests a systemic media processor bug rather than WhatsApp-specific code.

  • Related: Issue #2901 - Twitter DMs Inline Media Not Delivered

    Confirmed same root cause: inline MEDIA:/path in Twitter auto-replies fails while manual send works.

Reference Issues for Maintainers

When filing a PR to fix this issue, reference:

  • Issue: [BUG] WhatsApp auto-reply inline MEDIA:/absolute/path fails
  • Regression Versions: v2026.4.11 โ†’ v2026.4.14
  • Affected Path: src/core/media-processor.ts โ†’ normalizeMediaPath()
  • Test Coverage Gap: No integration test for MEDIA:/ scheme in auto-reply media delivery
  • Suggested Test:

typescript it(‘should handle MEDIA:/ URI scheme in auto-reply’, async () => { const processor = new MediaProcessor(); const result = processor.normalizeMediaPath(‘MEDIA:/absolute/path/image.png’); expect(result).toBe(’/absolute/path/image.png’); });

Evidence & Sources

This troubleshooting guide was automatically synthesized by the FixClaw Intelligence Pipeline from community discussions.