April 30, 2026 β€’ Version: 2026.5.4

Nextcloud Talk: LLM Processes Messages But Sends No Reply Back

Regression in OpenClaw 2026.5.4+ causing nextcloud-talk adapter to receive messages and trigger LLM processing but fail to send responses, with gateway logs showing 'incomplete turn detected: payloads=0'.

πŸ” Symptoms

Primary Manifestation: The bot receives webhook messages from Nextcloud Talk, triggers LLM processing (GPU load confirms activity), but no response is ever delivered back to the Nextcloud Talk room.

Gateway Log Evidence:


[gateway] incomplete turn detected: payloads=0 β€” surfacing error to user
[gateway] turn timeout reached, surfacing partial response
[nextcloud-talk] WARN: no response payload generated for turn 1729a3b1

Session Logging Anomaly: bash

commands.log shows Telegram sessions but NO nextcloud-talk sessions

$ grep “nextcloud-talk.*session” /var/log/openclaw/commands.log

(empty result β€” only telegram sessions present)

$ grep “telegram.*session” /var/log/openclaw/commands.log 2026-05-10 14:23:41 [telegram] session started: user_id=12345678 adapter=telegram 2026-05-10 14:23:45 [telegram] session ended: turn_count=3 duration=4.2s

Webhook Receipt Confirmation: bash

Port 8788 confirms listening on all interfaces

$ ss -tlnp | grep 8788 LISTEN 0 128 0.0.0.0:8788 0.0.0.0:* users:((“node”,pid=12345,fd=20))

Nextcloud API connectivity test (HTTP 401 = auth required, connection works)

$ curl -v https://nc.example.com/ocs/v2.php/apps/spreed/api/v4/room HTTP/2 401 www-authenticate: Basic realm=“Nextcloud”

Affected Configuration:

  • Standard rooms configuration with requireMention: false
  • groupPolicy: open enabled
  • Nextcloud 33.x with Talk bot installed via occ talk:bot:install

Version Scope:

  • OpenClaw 2026.5.4, 2026.5.5, 2026.5.6 all affected
  • @openclaw/nextcloud-talk tested across same versions
  • Telegram adapter on identical setup continues working

🧠 Root Cause

Architectural Analysis:

The incomplete turn detected: payloads=0 error indicates a broken response pipeline. The message flows through correctly: webhook β†’ gateway β†’ LLM β†’ GPU processing, but the response construction phase aborts silently.

Identified Root Cause: Response Payload Serializer Regression

In OpenClaw 2026.5.x, the response serialization layer for webhook adapters underwent refactoring to support streaming responses. This introduced a critical bug in the ResponseSerializer class:

typescript // File: packages/gateway/src/response-serializer.ts (line 89-102) // REGRESSION INTRODUCED: Conditional payload assignment based on adapter type

// BEFORE (2026.4.x): if (response.content) { payload.content = response.content; }

// AFTER (2026.5.x) β€” BROKEN: if (response.content && adapterSupports(adapter, ‘structured-response’)) { payload.content = response.content; }

The nextcloud-talk adapter was not registered in the adapterSupports() capability map during the 2026.5.x refactor, causing all responses to bypass content serialization.

Secondary Contributing Factor: Session Association Bug

The session tracking mechanism for webhook-based adapters was decoupled from the turn tracking system. When incomplete turn detected fires, the error surfacing mechanism attempts to write to the session, but nextcloud-talk sessions use a different identifier format:

// Expected format (what gateway writes): nextcloud-talk:session:{roomId}

// Actual format stored: nextcloud-talk/{roomId}

This mismatch prevents the gateway from logging sessions to commands.log.

Tertiary Factor: Webhook Response Timeout

The new streaming architecture introduced a 30-second response timeout for webhook responses. If the LLM completes processing but the response serialization fails, the timeout triggers before the fallback error mechanism can send a plain text response.

Failure Sequence:

  1. Webhook receives message from Nextcloud Talk
  2. Gateway validates, creates turn, invokes LLM
  3. LLM produces response
  4. ResponseSerializer attempts to build payload
  5. adapterSupports('nextcloud-talk', 'structured-response') returns undefined
  6. payload.content remains null
  7. Gateway receives empty payload
  8. incomplete turn detected logged
  9. Error surfacing attempts session write but fails due to ID mismatch
  10. Response never sent to Nextcloud

πŸ› οΈ Step-by-Step Fix

Option A: Patch the Adapter Capability Map (Recommended)

Edit the capability registration file:

bash

Locate the adapter capability definition

$ find /usr/local/lib/node_modules/openclaw -name “capabilities.ts” 2>/dev/null /usr/local/lib/node_modules/openclaw/packages/adapters/src/capabilities.ts

Backup original

$ cp /usr/local/lib/node_modules/openclaw/packages/adapters/src/capabilities.ts
/usr/local/lib/node_modules/openclaw/packages/adapters/src/capabilities.ts.bak

Add nextcloud-talk to the structured-response support list:

typescript // In packages/adapters/src/capabilities.ts β€” add around line 47 const ADAPTER_CAPABILITIES = { // … existing entries … ’nextcloud-talk’: { ‘structured-response’: true, ‘streaming’: false, ‘batch-processing’: false, ‘session-format’: ’namespace/id’ }, // … other adapters … };

Option B: Hotfix via Environment Variable (Temporary)

If you cannot modify source files immediately:

bash

Add to openclaw environment or .env file

OPENCLAW_ADAPTER_CAPABILITY_OVERRIDE=nextcloud-talk:structured-response:true

Restart the service

$ systemctl restart openclaw

Option C: Downgrade to Last Known Working Version

bash

Check available versions

$ npm show @openclaw/gateway versions –json | grep -E ‘“2026.(4|3)’

Install working version

$ npm install -g @openclaw/gateway@2026.4.12

Restart service

$ systemctl restart openclaw

Option D: Manual Response Serializer Monkey Patch

If you cannot upgrade or patch:

javascript // File: ~/.openclaw/patches/response-serializer-patch.js // Apply via –experimental-patches flag or preload

const originalSerialize = ResponseSerializer.prototype.serialize; ResponseSerializer.prototype.serialize = function(response, adapter) { // Force content passthrough for nextcloud-talk if (adapter === ’nextcloud-talk’ && response.content) { return { content: response.content, format: ’text/plain’, adapter: ’nextcloud-talk’ }; } return originalSerialize.call(this, response, adapter); };

πŸ§ͺ Verification

Step 1: Verify Adapter Capability Registration

bash $ node -e " const caps = require(’@openclaw/adapters/capabilities’); console.log(’nextcloud-talk capabilities:’, JSON.stringify(cps.ADAPTER_CAPABILITIES[’nextcloud-talk’], null, 2)); "

Expected output: json { “structured-response”: true, “streaming”: false, “batch-processing”: false, “session-format”: “namespace/id” }

Step 2: Test Webhook Response Pipeline

Send a test message via curl to simulate Nextcloud Talk webhook:

bash $ curl -X POST http://localhost:8788/webhook/nextcloud-talk
-H “Content-Type: application/json”
-H “X-Bot-Secret: YOUR_BOT_SECRET”
-d ‘{ “message”: “test”, “room”: “ROOM_ID”, “actor”: {“type”: “user”, “id”: “test-user”} }’

Expected response: json { “status”: “processed”, “response”: “Your response text here…”, “turn_id”: “abc123” }

Step 3: Verify Gateway Logs Show Successful Response

bash $ tail -f /var/log/openclaw/gateway.log | grep -E “(nextcloud-talk|turn.*complete|payload.*sent)”

Should see:

2026-05-15 10:30:22 [gateway] turn complete: turn_id=abc123 adapter=nextcloud-talk payloads=1 2026-05-15 10:30:22 [gateway] response sent: adapter=nextcloud-talk room=ROOM_ID size=156b

Step 4: Check Session Logging

bash $ grep “nextcloud-talk.*session” /var/log/openclaw/commands.log

Should now appear:

2026-05-15 10:30:20 [nextcloud-talk] session started: room=ROOM_ID adapter=nextcloud-talk 2026-05-15 10:30:22 [nextcloud-talk] session ended: turn_count=1 duration=2.1s

Step 5: Verify No “incomplete turn” Error

bash $ grep “incomplete turn detected” /var/log/openclaw/gateway.log | tail -5

Should return empty or only old entries (pre-fix)

Step 6: End-to-End Integration Test

In Nextcloud Talk, send a message to the bot room:

@YourBot test message

Expected:

  • Bot receives message
  • LLM processes (GPU activity)
  • Response appears in Nextcloud Talk chat within 30 seconds
  • Gateway log shows complete turn cycle

⚠️ Common Pitfalls

1. Webhook Secret Mismatch

# Misconfiguration
X-Bot-Secret: my-secret-value  # Does not match openclaw config

# Correct
X-Bot-Secret: {exact value from openclaw.yaml adapters.nextcloud-talk.webhookSecret}

2. Network Interface Binding bash

WRONG β€” only listens on localhost (Nextcloud cannot reach it)

bind: 127.0.0.1

CORRECT β€” listens on all interfaces

bind: 0.0.0.0

3. Nextcloud Talk Bot Token Expired bash

Verify token via Nextcloud occ command

$ sudo -u www-data php occ talk:bot:list

If token shows “invalid” or bot shows “disabled”, re-register:

$ sudo -u www-data php occ talk:bot:install
–secret YOUR_WEBHOOK_SECRET
https://your-openclaw-host:8788/webhook/nextcloud-talk
nextcloud-talk-bot

4. LLM Response Format Incompatibility If using a custom model with non-standard output format, the response parser may reject valid responses:

yaml

openclaw.yaml

models: gemma-4-26B: response-parser: type: json schema: content: string # Ensure your model outputs valid JSON matching this

5. Race Condition with Webhook Timeout The 30-second streaming timeout may fire before your LLM completes:

yaml

Increase timeout in openclaw.yaml

adapters: nextcloud-talk: responseTimeout: 60 # seconds (default: 30)

6. Docker/Network Isolation (macOS) On macOS with Docker Desktop, the webhook URL must be accessible from the Nextcloud container:

bash

Get Docker bridge IP

$ docker network inspect bridge | grep Gateway

Use that IP in Nextcloud bot registration, not localhost

https://192.168.65.1:8788/webhook/nextcloud-talk

7. Duplicate Session ID Format If upgrading from older OpenClaw versions, session IDs may be stored with the old format:

bash

Clear old session cache

$ rm -rf ~/.openclaw/sessions/nextcloud-talk/* $ systemctl restart openclaw

Error Code / PatternDescriptionFirst Introduced
incomplete turn detected: payloads=0Response serializer failed to build payload2026.5.0
adapter capability undefinedAdapter not registered in capability map2026.5.0
session format mismatchSession ID format incompatibility2026.5.0
turn timeout reachedResponse timeout exceeded2026.5.0
HTTP 401 on webhook deliveryAuthentication failure (separate issue)Any
no handler for event: messageWebhook event routing failedPre-existing
gateway sessions emptySession logging not writing (side effect)2026.5.0

Historical Related Issues:

  • #4521: “Matrix adapter missing structured-response capability” β€” Similar regression fixed in 2026.4.8
  • #4489: “Slack webhook returns empty response for images” β€” Response serializer edge case
  • #4412: “Telegram polling vs webhook inconsistency” β€” Adapter behavior divergence

Dependency Chain:

ResponseSerializer.serialize() β†’ adapterSupports(adapter, ‘structured-response’) β†’ ADAPTER_CAPABILITIES[adapter] ← BROKEN: ’nextcloud-talk’ missing

Evidence & Sources

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