Skip to content

fix: decode base64 image data before sending to Hyper3D API#194

Open
TGLEEEE wants to merge 1 commit intoahujasid:mainfrom
TGLEEEE:main
Open

fix: decode base64 image data before sending to Hyper3D API#194
TGLEEEE wants to merge 1 commit intoahujasid:mainfrom
TGLEEEE:main

Conversation

@TGLEEEE
Copy link

@TGLEEEE TGLEEEE commented Feb 26, 2026

The MCP server transmits image data as base64-encoded strings over the JSON socket connection to the Blender addon. However, the addon was passing this string directly to the requests library's files= parameter, which expects bytes. This caused a serialization error when calling the Hyper3D API.

Fix by decoding the base64 string back to bytes before constructing the multipart form data.

Summary by CodeRabbit

  • Bug Fixes
    • Fixed image data processing to ensure proper formatting before transmission to the API.

…ITE mode

The MCP server transmits image data as base64-encoded strings over the 
JSON socket connection to the Blender addon. However, the addon was passing 
this string directly to the requests library's `files=` parameter, which 
expects bytes. This caused a serialization error when calling the Hyper3D API.

Fix by decoding the base64 string back to bytes before constructing the 
multipart form data.
@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

📝 Walkthrough

Walkthrough

The create_rodin_job_main_site function in addon.py now base64-decodes image strings before including them in the API payload. For each image item, if the value is a string, it is decoded from base64; otherwise, it remains unchanged. This ensures binary image data is transmitted to the Rodin API rather than base64-encoded text.

Changes

Cohort / File(s) Summary
Image Payload Preparation
addon.py
Modified create_rodin_job_main_site to decode base64-encoded image strings to binary format before sending to the Rodin API.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related issues

  • Issue #177: Directly addresses the bug of sending base64-encoded text instead of binary image data to the Rodin API during uploads.

Poem

🐰 A rabbit's tale of bytes so fine,
Base64 strings to binary align,
No more text where images should gleam,
Rodin's API now works supreme!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: decoding base64 image data before sending to the API, which matches the PR's core fix of converting base64-encoded strings to bytes for proper serialization.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link

Review Summary by Qodo

Decode base64 images before Hyper3D API submission

🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Decode base64 image strings to bytes before API submission
• Fix serialization error in Hyper3D API multipart form data
• Handle both string and bytes image data types safely
Diagram
flowchart LR
  A["Base64 image string"] -->|b64decode| B["Bytes data"]
  B -->|multipart form| C["Hyper3D API request"]
  D["Bytes data"] -->|passthrough| C
Loading

Grey Divider

File Changes

1. addon.py 🐞 Bug fix +1/-1

Decode base64 images in multipart form data

• Modified create_rodin_job_main_site method to decode base64 image strings
• Added conditional check to handle both string and bytes image formats
• Applied base64.b64decode() to image data in multipart form construction
• Ensures requests library receives bytes instead of base64 strings

addon.py


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Feb 26, 2026

Code Review by Qodo

🐞 Bugs (1) 📘 Rule violations (1) 📎 Requirement gaps (0)

Grey Divider


Action required

1. Unvalidated b64decode(img) input 📘 Rule violation ⛨ Security
Description
The new base64.b64decode(img) path decodes external image strings without validation or explicit
handling of invalid/empty/non-base64 inputs, which can raise runtime exceptions and fail the API
call. This does not meet the requirement to validate external inputs and handle edge cases with
actionable context.
Code

addon.py[1191]

+                *[("images", (f"{i:04d}{img_suffix}", base64.b64decode(img) if isinstance(img, str) else img)) for i, (img_suffix, img) in enumerate(images)],
Evidence
Compliance requires validating external inputs and handling edge cases/errors with meaningful
context. The changed code decodes img when it is a str, but provides no validation (e.g., base64
validity) or targeted handling for decode failures at this new failure point.

Rule 3: Generic: Robust Error Handling and Edge Case Management
Rule 6: Generic: Security-First Input Validation and Data Handling
addon.py[1191-1191]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`base64.b64decode(img)` is applied to external `img` strings without validation or targeted error handling, so invalid/empty/non-base64 input can raise exceptions and break Rodin job creation.

## Issue Context
`images` data comes from outside this function (socket/JSON flow per PR description), so it should be treated as untrusted input and decoded defensively.

## Fix Focus Areas
- addon.py[1186-1194] ისე

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Type hint mismatch 🐞 Bug ✓ Correctness
Description
create_rodin_job_main_site now accepts either base64 str (decoded to bytes) or raw bytes, but
its images parameter annotation still states list[tuple[str, str]]. This can mislead callers and
tooling about the actual contract after the change.
Code

addon.py[1191]

+                *[("images", (f"{i:04d}{img_suffix}", base64.b64decode(img) if isinstance(img, str) else img)) for i, (img_suffix, img) in enumerate(images)],
Evidence
The function signature claims images elements are (suffix: str, img: str), but the new logic
explicitly supports non-str image payloads by passing them through unchanged. The MCP server
currently sends base64-encoded ASCII strings, so the intended input type is base64 str (at least),
and the function now also supports bytes.

addon.py[1180-1194]
src/blender_mcp/server.py[867-875]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`create_rodin_job_main_site` now decodes base64 strings to bytes (or passes bytes through), but its type annotation still claims `images` is `list[tuple[str, str]]`. This makes the function contract inaccurate for callers and static tooling.

## Issue Context
The MCP server constructs `images` as `(suffix, base64_string)` tuples; the addon now decodes these strings to bytes before sending them via `requests` multipart upload.

## Fix Focus Areas
- addon.py[1180-1194]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
addon.py (1)

1180-1209: The base64 decoding fix is correct and addresses the API serialization issue.

The change correctly decodes base64 strings to bytes before passing to requests.files=, which expects binary data. The conditional isinstance(img, str) properly handles both cases (base64 strings from MCP server and direct bytes).

Two minor suggestions:

  1. Type annotation mismatch: The type hint on line 1183 still says list[tuple[str, str]], but the second element can now be str (base64) or bytes. Consider updating for clarity.

  2. Docstring placement: The docstring on line 1189 appears after the if images is None guard. It should be the first statement in the function body.

,

💡 Optional: Update type hint and fix docstring placement
 def create_rodin_job_main_site(
         self,
         text_prompt: str=None,
-        images: list[tuple[str, str]]=None,
+        images: list[tuple[str, str | bytes]]=None,
         bbox_condition=None
     ):
+    """Call Rodin API, get the job uuid and subscription key"""
     try:
         if images is None:
             images = []
-        """Call Rodin API, get the job uuid and subscription key"""
         files = [
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@addon.py` around lines 1180 - 1209, In create_rodin_job_main_site, move the
docstring so it is the first statement in the function body (place it
immediately after the signature, before the "if images is None" guard) and
update the type annotation for the images parameter to reflect that the second
tuple element can be either str (base64) or bytes (e.g., use Union[str, bytes]
or the bytes | str union syntax depending on project typing style); ensure any
needed typing imports (Union) are added/adjusted accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@addon.py`:
- Around line 1180-1209: In create_rodin_job_main_site, move the docstring so it
is the first statement in the function body (place it immediately after the
signature, before the "if images is None" guard) and update the type annotation
for the images parameter to reflect that the second tuple element can be either
str (base64) or bytes (e.g., use Union[str, bytes] or the bytes | str union
syntax depending on project typing style); ensure any needed typing imports
(Union) are added/adjusted accordingly.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7636d13 and 989300d.

📒 Files selected for processing (1)
  • addon.py

"""Call Rodin API, get the job uuid and subscription key"""
files = [
*[("images", (f"{i:04d}{img_suffix}", img)) for i, (img_suffix, img) in enumerate(images)],
*[("images", (f"{i:04d}{img_suffix}", base64.b64decode(img) if isinstance(img, str) else img)) for i, (img_suffix, img) in enumerate(images)],

Choose a reason for hiding this comment

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

Action required

1. Unvalidated b64decode(img) input 📘 Rule violation ⛨ Security

The new base64.b64decode(img) path decodes external image strings without validation or explicit
handling of invalid/empty/non-base64 inputs, which can raise runtime exceptions and fail the API
call. This does not meet the requirement to validate external inputs and handle edge cases with
actionable context.
Agent Prompt
## Issue description
`base64.b64decode(img)` is applied to external `img` strings without validation or targeted error handling, so invalid/empty/non-base64 input can raise exceptions and break Rodin job creation.

## Issue Context
`images` data comes from outside this function (socket/JSON flow per PR description), so it should be treated as untrusted input and decoded defensively.

## Fix Focus Areas
- addon.py[1186-1194] ისე

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant