Skip to content

Conversation

@codomposer
Copy link
Contributor

@codomposer codomposer commented Nov 20, 2025

Summary

Closes #1756

Bug Fix Summary: files_upload_v2 internal_error with markdown blocks

Problem

When using files_upload_v2() with a blocks parameter containing markdown blocks, the Slack API returned an internal_error:

blocks = [{"type": "markdown", "text": "_**Haim Raitsev** posted a new message_\\n> test"}]
response = await client.files_upload_v2(
    channel=channel_id,
    file_uploads=[...],
    blocks=json.dumps(blocks)  # or just blocks=blocks
)
# Result: {"ok": False, "error": "internal_error"}

Root Cause

The files_completeUploadExternal() method (called internally by files_upload_v2()) was not properly handling the blocks and attachments parameters:

  1. Missing _parse_web_class_objects() call: This function converts Block objects to dictionaries, but it wasn't being called
  2. Missing JSON serialization: The blocks and attachments parameters need to be JSON-serialized strings when passed via params=kwargs, but they were being passed as Python lists
  3. Inconsistent with other methods: Methods like chat.postMessage() properly handle blocks by calling _parse_web_class_objects() and using json=kwargs (which auto-serializes) or manually serializing to JSON strings

Solution

Modified files_completeUploadExternal() in both slack_sdk/web/client.py and slack_sdk/web/async_client.py:

Changes in slack_sdk/web/client.py (lines 4115-4126):

# Parse Block objects and serialize blocks/attachments to JSON
_parse_web_class_objects(kwargs)

# Serialize blocks to JSON if present and not already a string
blocks = kwargs.get("blocks")
if blocks is not None and not isinstance(blocks, str):
    kwargs["blocks"] = json.dumps(blocks)

# Serialize attachments to JSON if present and not already a string
attachments = kwargs.get("attachments")
if attachments is not None and not isinstance(attachments, str):
    kwargs["attachments"] = json.dumps(attachments)

What the fix does:

  1. Calls _parse_web_class_objects(kwargs): Converts any Block/Attachment objects to dictionaries
  2. Serializes blocks to JSON: If blocks is a list (not already a string), converts it to a JSON string
  3. Serializes attachments to JSON: Same treatment for attachments parameter
  4. Preserves already-serialized data: If blocks/attachments are already JSON strings, they're left unchanged

Files Modified

  • slack_sdk/web/client.py - Added blocks/attachments serialization logic
  • slack_sdk/web/async_client.py - Auto-regenerated with the same fix using scripts/codegen.py
  • slack_sdk/web/legacy_client.py - Auto-regenerated with the same fix using scripts/codegen.py

Usage Examples

Before (would cause internal_error):

blocks = [{"type": "markdown", "text": "_**User** posted a message_\\n> test"}]
response = await client.files_upload_v2(
    channel=channel_id,
    file_uploads=[{"content": b"data", "filename": "file.png"}],
    blocks=blocks  # This would fail
)

After (works correctly):

# Option 1: Pass as list of dicts (recommended)
blocks = [{"type": "markdown", "text": "_**User** posted a message_\\n> test"}]
response = await client.files_upload_v2(
    channel=channel_id,
    file_uploads=[{"content": b"data", "filename": "file.png"}],
    blocks=blocks  # Now works!
)

# Option 2: Pass as Block objects
from slack_sdk.models.blocks import MarkdownBlock
blocks = [MarkdownBlock(text="_**User** posted a message_\\n> test")]
response = await client.files_upload_v2(
    channel=channel_id,
    file_uploads=[{"content": b"data", "filename": "file.png"}],
    blocks=blocks  # Also works!
)

# Option 3: Pass as JSON string (still supported)
blocks = json.dumps([{"type": "markdown", "text": "_**User** posted a message_\\n> test"}])
response = await client.files_upload_v2(
    channel=channel_id,
    file_uploads=[{"content": b"data", "filename": "file.png"}],
    blocks=blocks  # Still works!
)

Impact

This fix ensures that files_upload_v2() properly handles the blocks parameter in all its forms (list of dicts, Block objects, or JSON strings), making it consistent with other Slack SDK methods like chat.postMessage().

Category

  • slack_sdk.web.WebClient (sync/async) (Web API client)
  • slack_sdk.webhook.WebhookClient (sync/async) (Incoming Webhook, response_url sender)
  • slack_sdk.socket_mode (Socket Mode client)
  • slack_sdk.signature (Request Signature Verifier)
  • slack_sdk.oauth (OAuth Flow Utilities)
  • slack_sdk.models (UI component builders)
  • slack_sdk.scim (SCIM API client)
  • slack_sdk.audit_logs (Audit Logs API client)
  • slack_sdk.rtm_v2 (RTM client)
  • /docs (Documents)
  • /tutorial (PythOnBoardingBot tutorial)
  • tests/integration_tests (Automated tests for this library)

Requirements

  • I've read and understood the Contributing Guidelines and have done my best effort to follow them.
  • I've read and agree to the Code of Conduct.
  • I've run python3 -m venv .venv && source .venv/bin/activate && ./scripts/run_validation.sh after making the changes.

Contribution by Gittensor, learn more at https://gittensor.io/

@codomposer codomposer requested a review from a team as a code owner November 20, 2025 22:31
@codomposer
Copy link
Contributor Author

@zimeg
can you please check this pull request?

@mwbrooks mwbrooks added bug M-T: A confirmed bug report. Issues are confirmed when the reproduction steps are documented semver:patch labels Nov 20, 2025
@mwbrooks mwbrooks modified the milestones: 3.40.0, 3.x Nov 20, 2025
@mwbrooks
Copy link
Member

Very high quality PR @codomposer ❤️ ⚡

Thanks for also updating the legacy client and adding tests for each scenario. 👌🏻 I'll let @zimeg give it a review when they're available.

@zimeg zimeg changed the title fix handling markdown blocks in files_upload_v2 function fix: handling markdown blocks in files_upload_v2 function Nov 20, 2025
Copy link
Member

@zimeg zimeg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codomposer Hmm I'm not confident the files.completeUploadExternal method is accepting the markdown block at this time and might require additional changes on the backend. FWIW other blocks appear to send as expected for me! 🤖

I did leave a comment on an alternative approach to this change as well, but please let me know if I'm overlooking something when testing these API calls.

@codomposer
Copy link
Contributor Author

hi @zimeg
any update on this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug M-T: A confirmed bug report. Issues are confirmed when the reproduction steps are documented cla:signed semver:patch

Projects

None yet

Development

Successfully merging this pull request may close these issues.

files_upload_v2 returns internal_error when using markdown in blocks

3 participants