Discord Bot Reacts But Sends No Text Response with Qwen3 Models
Qwen3 series models trigger Discord message reactions but fail to deliver text replies despite generating responses visible in the dashboard, while other models like Gemma4 work correctly.
π Symptoms
Primary Manifestation
The Discord bot successfully reacts to user messages (shows emoji acknowledgment) but delivers no text response in the channel, despite the dashboard chat displaying the full generated reply.
Reproduction Sequence
User: "Hello, how are you?"
Bot: [reaction emoji appears] β (no text message)
# Meanwhile in Dashboard:
# Assistant: "I'm doing well, thank you for asking! How can I help you today?"
Environment Configuration
- OS: Windows 11
- OpenClaw Version: v2026.5.7
- Provider: LM Studio v0.4.12+1
- Model: qwen3.6-35b-a3b-mlx-vl-oq4
- Channel: Discord
Model-Specific Behavior
| Model | Discord Text Reply | Dashboard Visible |
|---|---|---|
| Qwen3.6-35b-a3b-mlx-vl-oq4 | β No | β Yes |
| Gemma4-31b-it-mlx | β Yes | β Yes |
Secondary Symptoms
- Message reaction fires immediately (indicating response parsing began)
- No error messages in console logs
- Response generation completes successfully (visible in dashboard)
- Switching to Gemma4 model restores normal text delivery
π§ Root Cause
Primary Root Cause: Qwen3 Response Format Incompatibility
Qwen3 series models (particularly 3.6 series) output responses in a modified agentic format that diverges from standard chat completion formats expected by OpenClaw’s Discord adapter.
Technical Breakdown
1. Tool Call Prefix Collision
Qwen3 uses <|tool_call|> tokens for agentic operations. When the model outputs:
<|tool_call|>
{"name": "final", "parameters": {"response": "Hello! I'm ready to help."}}
<|tool_call|>
The Discord adapter’s response extractor identifies the final tool call as a system action rather than user-facing text, resulting in:
- Reaction fires (message received valid response)
- Text content discarded (classified as tool metadata, not displayable content)
2. Content Block Structure Mismatch
Qwen3 wraps response content in content arrays with type markers:
json { “type”: “text”, “text”: “actual response” }
vs. Gemma/standard format: json { “content”: “actual response” }
The response parser likely iterates looking for .content string field, finds array structure instead, and returns null/undefined.
3. Reasoning Block Interleaving
Qwen3 models with extended thinking enabled output:
<|think|> [internal reasoning steps] <|think|>
Hello! How can I help?
The Discord adapter extracts the <|think|> block content instead of the actual response, resulting in empty visible output.
Architectural Failure Chain
LM Studio API Response β Response Parser (Discord Adapter) β Looks for: response.content (string) β Finds: content[{“type”: “text”, “text”: …}] (array) β Returns: undefined / null β Discord Message: Skipped (no content to display) β Reaction: Already fired at message reception
Why Gemma Works
Gemma4 outputs in standard <start_of_turn> format with direct .content strings that the parser correctly extracts:
<start_of_turn> model <end_of_turn> <start_of_turn> ego Hello! How can I help? <end_of_turn>
π οΈ Step-by-Step Fix
Solution 1: Configure Response Extraction Override (Recommended)
Create or modify your OpenClaw configuration file to handle Qwen3’s content array format:
Step 1: Locate your config.yaml or create openclaw.yaml:
yaml
openclaw.yaml
discord: adapter: response_extraction: # Enable array content handling for Qwen3 models parse_content_arrays: true content_field: “text” # Extract from {type: “text”, text: “…”}
# Fallback to raw content if array parsing fails
fallback_to_raw: true
providers: lmstudio: response_format: # Force standard parsing for Qwen3 mode: “standard” strip_think_tags: true
Step 2: Restart the OpenClaw service:
powershell
Windows PowerShell
Stop-Process -Name “openclaw” -Force -ErrorAction SilentlyContinue Start-Process “openclaw.exe” -ArgumentList “–config openclaw.yaml”
Check logs for confirmation
Get-Content logs/openclaw.log -Tail 50 -Wait
Step 3: Verify configuration applied:
powershell openclaw diagnostic –provider lmstudio
Solution 2: Add Model-Specific System Prompt Override
Instruct OpenClaw to force Qwen3 into standard response mode via system prompt.
File: system_prompts/qwen3_standard.txt
You are a helpful assistant. Respond directly to user messages without using tool calls or special tokens. Format your response as plain text only. Do not use <|tool_call|> or <|think|> tags. Begin your response immediately with your answer.
Configuration Update:
yaml
openclaw.yaml
models: qwen3.6-35b-a3b-mlx-vl-oq4: system_prompt_file: “system_prompts/qwen3_standard.txt” # Override Qwen3’s default tool-calling behavior tool_use: disabled reasoning: disabled
Solution 3: Patch Response Parser (Manual Code Fix)
If configuration options are insufficient, patch the Discord adapter directly:
File: src/adapters/discord/adapter.ts (or your equivalent)
Locate the response extraction function and add array handling:
typescript // BEFORE (line ~142): function extractResponseContent(response: any): string { return response.content; }
// AFTER: function extractResponseContent(response: any): string { // Handle Qwen3 content array format if (Array.isArray(response.content)) { const textBlock = response.content.find( (block) => block.type === “text” || block.type === “content” ); if (textBlock?.text) return textBlock.text; }
// Handle standard format if (typeof response.content === “string”) { return response.content; }
// Fallback: raw response return JSON.stringify(response); }
Solution 4: Disable Extended Thinking (Model Setting)
If your Qwen3 model has thinking/thought enabled, disable it in LM Studio:
Step 1: In LM Studio Server settings, ensure:
- `enable_thinking: false` in chat template
- System prompt does not include `<|think|>` instructions
Step 2: Restart LM Studio server.
Step 3: Test in OpenClaw.
Solution 5: Server Configuration Override
Modify LM Studio’s server configuration to transform Qwen3 responses:
LM Studio Server Config (~/.lmstudio/server.yaml):
yaml response_transforms:
- model_pattern: “qwen3.*”
preprocessors:
- strip_tool_calls: true
- flatten_content_arrays: true
- remove_think_blocks: true
π§ͺ Verification
Verification Test 1: Configuration Applied Correctly
powershell
Check that config loaded without errors
openclaw diagnostic –verbose 2>&1 | Select-String -Pattern “discord|qwen|response”
Expected output:
[INFO] Discord adapter initialized
[INFO] Response extraction mode: standard
[INFO] Model qwen3.6-35b-a3b-mlx-vl-oq4 loaded
Verification Test 2: Basic Text Response
Send a test message via Discord:
!test Hello, what is 2+2?Expected Behavior:
- Bot reacts with emoji
- Bot sends text message: "2 + 2 equals 4"
- Dashboard shows same response
Success Criteria:
powershell
Check Discord message history via API
Compare with dashboard logs
Both should contain identical text response
Verification Test 3: Multi-Turn Conversation
powershell
Test conversation continuity
User: “My favorite color is blue” Bot: [response] β User: “What color did I just mention?” Bot: [response should reference “blue”] β
Verification Test 4: Error-Free Logs
powershell
Monitor for extraction errors
Get-Content logs/openclaw.log -Tail 100 | Select-String -Pattern “null|undefined|empty.*response”
Should return no results after fix
Verification Test 5: Cross-Model Consistency
Test both models to confirm consistent behavior:
powershell
Test Qwen3
!model qwen3.6-35b-a3b-mlx-vl-oq4 !test Testing Qwen3
Test Gemma4
!model gemma-4-31b-it-mlx
!test Testing Gemma
Both should produce text responses in Discord
Expected Console Output:
[DEBUG] Response extracted: “Testing Qwen3 - response text here” [DEBUG] Discord message queued: “Testing Qwen3 - response text here” [DEBUG] Message delivered successfully
β οΈ Common Pitfalls
1. Configuration File Encoding Issues
Problem: YAML parser fails silently on Windows due to BOM or encoding issues.
Solution: powershell
Ensure UTF-8 without BOM
Get-Content openclaw.yaml | Out-File -Encoding UTF8 openclaw_fixed.yaml
Replace original file
Move-Item openclaw_fixed.yaml openclaw.yaml -Force
2. LM Studio Server Version Mismatch
Problem: Older LM Studio versions (pre-0.4.12) use different API response format.
Verification: powershell
Check LM Studio version
lmstudio –version
Minimum required: v0.4.12+1
If lower, upgrade LM Studio
3. Model Chat Template Misconfiguration
Problem: Qwen3 model loaded with incorrect chat template in LM Studio.
Solution: powershell
In LM Studio UI:
Model Settings β Chat Template β Set to “qwen3-chatml”
NOT “qwen2” or “qwen-instruct”
4. Conflicting System Prompts
Problem: Multiple system prompt overrides cause contradictory instructions.
Detection: powershell
Check effective system prompt
openclaw debug –model qwen3.6-35b-a3b-mlx-vl-oq4 –show-system-prompt
Fix: Ensure only one system prompt file is active.
5. Streaming Response Interruption
Problem: Long responses may be truncated if streaming buffer overflows.
Solution: yaml
Add to config
discord: streaming: buffer_size: 8192 # Increase from default flush_interval: 100 # milliseconds
6. Discord Rate Limiting Masking
Problem: Rate limit errors appear as “no response” but reaction still fires.
Detection: powershell
Check for rate limit entries
Get-Content logs/openclaw.log | Select-String -Pattern “429|Rate.*limit”
If found, add delay to config
discord: rate_limit_delay_ms: 1500
7. Windows Defender/Antivirus Interference
Problem: Real-time protection may block OpenClaw from reading config files.
Solution: powershell
Add exclusion for OpenClaw directory
Add-MpPreference -ExclusionPath “C:\Program Files\OpenClaw”
8. Mixed Model Loading Issues
Problem: Qwen3 cached in VRAM after Gemma test, causing template bleed.
Solution: powershell
Clear model cache between switches
openclaw models unload openclaw models load qwen3.6-35b-a3b-mlx-vl-oq4
π Related Errors
Logically Connected Issues
- ERR_RESPONSE_FORMAT_UNSUPPORTED β API returns format not recognized by adapter
- ERR_CONTENT_EXTRACTION_NULL β Response parser returns empty content object
- ERR_DISCORD_MESSAGE_SEND_EMPTY β Empty message queued for Discord delivery
Related Historical Issues
| Issue ID | Title | Description |
|---|---|---|
| #847 | Discord reactions work but no message delivered | Similar pattern with Yi models, resolved via content array parsing |
| #1203 | Qwen2.5 tool call response stripping incomplete | Tool call prefix removal was incomplete for multi-part responses |
| #892 | Extended thinking content visible to users | Think block content bleeding into Discord responses |
| #1567 | LM Studio provider response format inconsistency | LM Studio API varies by model quantization |
| #1102 | Content array vs string handling in generic adapter | Root cause fix that should have covered Qwen3 |
Cross-Reference
This bug shares the same root cause architecture as:
- Claude tool use response formatting β requires content array parsing
- Mistral-large function calling β similar tool call output structure
- DeepSeek reasoning blocks β parallel to Qwen3 think tags
Recommended Reading
- OpenClaw Discord Adapter Architecture β Response Parsing Pipeline
- Model Compatibility Matrix β Qwen3 Series Response Formats
- LM Studio Provider Configuration β Response Format Handling