hermes - 💡(How to fix) Fix [feishu] Fix markdown table rendering: use post+tag:md instead of force-text workaround

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…

This is a proposed fix for the known issue where markdown tables render as raw text in Feishu messages (related: #9549, #25452, #21866, #21778).

While #26658 proposes removing the _MARKDOWN_TABLE_RE workaround entirely, this issue presents an alternative approach that keeps the table detection but switches the output format from msg_type: text to msg_type: post + tag: md, which renders tables correctly in Feishu.

Root Cause

This is a proposed fix for the known issue where markdown tables render as raw text in Feishu messages (related: #9549, #25452, #21866, #21778).

While #26658 proposes removing the _MARKDOWN_TABLE_RE workaround entirely, this issue presents an alternative approach that keeps the table detection but switches the output format from msg_type: text to msg_type: post + tag: md, which renders tables correctly in Feishu.

Fix Action

Fix / Workaround

While #26658 proposes removing the _MARKDOWN_TABLE_RE workaround entirely, this issue presents an alternative approach that keeps the table detection but switches the output format from msg_type: text to msg_type: post + tag: md, which renders tables correctly in Feishu.

I have built and tested this approach as a standalone patch tool: feishu-table-patch

The patch:

  • Injects a _build_post_with_md() helper method into FeishuAdapter
  • Adds table detection at the top of _build_outbound_payload that returns a post + tag: md payload
  • Falls through to original logic when no table is detected
  • Is idempotent and reversible (can be uninstalled cleanly)
  • Auto-detects the method's indentation style and parameter name for compatibility

Code Example

_MARKDOWN_TABLE_RE = re.compile(r"^\|.*\|\n\|[-|: ]+\|", re.MULTILINE)

# In _build_outbound_payload:
if _MARKDOWN_TABLE_RE.search(content):
    text_payload = {"text": content}
    return "text", json.dumps(text_payload, ensure_ascii=False)

---

if _MARKDOWN_TABLE_RE.search(content):
    post_payload = {
        "zh_cn": {
            "title": "",
            "content": [[{"tag": "md", "text": content}]],
        }
    }
    return "post", json.dumps(post_payload, ensure_ascii=False)
RAW_BUFFERClick to expand / collapse

Summary

This is a proposed fix for the known issue where markdown tables render as raw text in Feishu messages (related: #9549, #25452, #21866, #21778).

While #26658 proposes removing the _MARKDOWN_TABLE_RE workaround entirely, this issue presents an alternative approach that keeps the table detection but switches the output format from msg_type: text to msg_type: post + tag: md, which renders tables correctly in Feishu.

The Problem

In gateway/platforms/feishu.py, _build_outbound_payload detects markdown tables and forces msg_type: text:

_MARKDOWN_TABLE_RE = re.compile(r"^\|.*\|\n\|[-|: ]+\|", re.MULTILINE)

# In _build_outbound_payload:
if _MARKDOWN_TABLE_RE.search(content):
    text_payload = {"text": content}
    return "text", json.dumps(text_payload, ensure_ascii=False)

This causes tables to display as raw pipe-delimited text, which is unreadable.

The Fix

Instead of falling back to plain text, send the content as a post message with tag: md, which supports full GFM markdown including tables:

if _MARKDOWN_TABLE_RE.search(content):
    post_payload = {
        "zh_cn": {
            "title": "",
            "content": [[{"tag": "md", "text": content}]],
        }
    }
    return "post", json.dumps(post_payload, ensure_ascii=False)

The Feishu post message type with tag: md supports all GFM syntax (tables, bold, italic, code blocks, lists, links, etc.), not just tables. This means the fix also improves rendering for any markdown content that contains tables alongside other formatting.

Why post + tag: md instead of interactive card?

  • Feishu interactive cards (msg_type: interactive) with tag: markdown render tables as plain text
  • Feishu post messages (msg_type: post) with tag: md render tables correctly as rich text
  • The post format is lighter weight than cards and more appropriate for simple content display

Reference Implementation

I have built and tested this approach as a standalone patch tool: feishu-table-patch

The patch:

  • Injects a _build_post_with_md() helper method into FeishuAdapter
  • Adds table detection at the top of _build_outbound_payload that returns a post + tag: md payload
  • Falls through to original logic when no table is detected
  • Is idempotent and reversible (can be uninstalled cleanly)
  • Auto-detects the method's indentation style and parameter name for compatibility

The key insight from testing: msg_type: post + tag: md is the correct Feishu API combination for rendering GFM tables. The tag: markdown in interactive cards does NOT render tables — only tag: md in post messages does.

Impact

  • Only affects the Feishu/Lark platform adapter
  • Non-table messages are completely unaffected (fall through to original logic)
  • No LLM involvement — the conversion happens at the adapter level, zero token cost
  • The title field in post messages is optional (can be empty string per Feishu API docs)

Alternative to #26658

While #26658 proposes removing the table detection entirely (relying on Feishu having fixed the original rendering bug), this approach keeps the detection but changes the output format. Benefits:

  • More defensive — if Feishu's md tag rendering regresses, the explicit post format still works
  • The post + tag: md format is specifically designed for rich text content, making it semantically more appropriate than the generic markdown post pipeline
  • Provides a clear, testable code path for table content

Happy to open a PR if the maintainers prefer this approach.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

hermes - 💡(How to fix) Fix [feishu] Fix markdown table rendering: use post+tag:md instead of force-text workaround