I am trying to build a workflow that downloads files from Slack and uploads them to Redmine.
The workflow contains two HTTP Request nodes: DownloadFileFromSlackDownloads the file successfully from Slack UploadFilesToRedmineIntended to upload the downloaded file to Redmine
The problem occurs when I pass the output of DownloadFileFromSlack directly into UploadFilesToRedmine.
The workflow execution fails with the following error:
Workflow execution had an error Error:
Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'res' -> object with constructor 'Object'
| property 'socket' -> object with constructor 'Object'
--- property '_httpMessage' closes the circle
Problem executing workflow
There was a problem executing the workflow.
Error: Converting circular structure to JSON
--> starting at object with constructor 'Object'
| property 'res' -> object with constructor 'Object'
| property 'socket' -> object with constructor 'Object'
--- property '_httpMessage' closes the cir
Expected behavior:
The binary file downloaded from Slack should be passed to the second HTTP Request node and uploaded to Redmine without serialization errors.
Actual behavior:
The workflow crashes before the upload request is executed.
Notes:
File download from Slack works correctly.
The issue appears only when forwarding the result into another HTTP Request node.
The binary file is definitely present in the output of DownloadFileFromSlack.
Also, if I disable Send Body in UploadFilesToRedmine, the workflow executes successfully, and I get a normal Redmine API error due to the missing file payload, which is expected.
So the issue is very likely not with the Slack download step or missing data, but specifically with how the binary file is being handled/serialized when it is passed into the UploadFilesToRedmine HTTP Request node in n8n Binary File mode.
Welcome to the community, @DmitryMigunov! Interesting case, and glad @jmoura found a fix.
Here’s why the Form-Data approach works: when you set Body Content Type to “n8n Binary File” directly (not wrapped in Form-Data), n8n tries to serialize the entire item including the internal metadata attached to binary data, which contains circular references like res -> socket -> _httpMessage that JSON.stringify can’t handle. That’s exactly what the error is pointing to.
When you switch to Form-Data with the field type set to n8n Binary File, n8n instead handles the binary as a proper multipart stream attachment, bypassing the JSON serialization entirely. The file bytes get sent as-is rather than going through any JSON encoding step, so the circular reference never triggers.
The Redmine API for uploading files expects a raw binary upload or multipart form-data anyway, so Form-Data is actually the more correct approach for this use case.
@DmitryMigunov if jmoura’s solution worked for you, it’d be great if you could mark it as the Solution so others running into this Slack-to-Redmine pattern can find the answer quickly!
Update: unfortunately, this still doesn’t fully solve the issue.
Even though the request now matches the Redmine documentation more closely (Body Content Type = Raw, Content-Type: application/octet-stream, and sending the binary data), the files are still coming through as corrupted on the Redmine side.
So it seems the request format is correct in principle, but the actual binary payload being sent via n8n is not being preserved properly when using the Raw body mode.
Thanks for the updates. Based on what you tested, I don’t think this is a binary field name issue anymore. The file exists as binary data, and the Redmine request format seems closer now, but the corruption suggests the bytes may not be preserved when sent through Raw body mode.
Since you are running n8n in queue/HA mode, I would also check your binary data storage. If binary data is stored on local filesystem, all workers/webhook/main pods need access to the same persistent storage, otherwise binary handling can become unreliable across executions.
As a workaround, I would avoid sending the binary through a Raw body expression. I would either upload it from the same execution context with a Code node or store the file temporarily in shared storage like S3/MinIO, then upload the real file bytes from there to Redmine.
Just to clarify — when you suggest using a Code node for uploading, do you mean something like using this.helpers.requestWithAuthentication inside the Code node?
Yes, that is the general idea, but I think the specific helper name is the issue here.
I would not use this.helpers.requestWithAuthentication in the Code node. That helper is not available there in that form. The helper exposed in n8n node development is httpRequestWithAuthentication, and the older request helper was deprecated.That said, for this case I would still avoid putting the whole upload logic in a Code node if possible, because credential access from Code nodes can be limited depending on context and version.
My safer approach would be to split it into two steps. First, use a Slack HTTP Request or Slack node to download the file as binary. Then use an HTTP Request node for Redmine, with authentication configured in the node itself, and send the body as the real binary file with application/octet-stream. If the HTTP Request node keeps corrupting the file, then I would move this upload to a very small external helper service instead of the Code node. The helper service would receive the Slack file URL and filename, stream the bytes directly to Redmine, and return the Redmine upload token back to n8n.
@DmitryMigunov Totally get the confusion here! @tamy.santos nailed it. The this.helpers.requestWithAuthentication API is only available inside custom node development (TypeScript), not inside the n8n Code node at runtime.
The cleanest approach for your Slack-to-Redmine file upload without a Code node would be:
Step 1 (HTTP Request node): Download the file from Slack
Body: send the binary data from Step 1 as application/octet-stream
The key thing is Step 1 must output a binary/file not JSON, then Step 2 picks it up directly. No Code node needed, and no circular structure issues at all.
If you want to try this and it works for you, feel free to mark the most useful reply as Solution so future searchers can find it!
for the Redmine upload endpoint, I would make sure the request matches the Redmine format exactly: POST /uploads.json?filename=your-file-name.jpg
Content-Type: application/octet-stream
request body should be the raw file bytes
also, from your screenshot, I see that the filename query parameter has this error: Referenced node doesn’t exist. So the expression is not resolving correctly. I would fix that first. If the file name is already in the current item, use something like: {{ $json.file.name }} or reference the actual existing node name exactly as it appears in your workflow.
@DmitryMigunov Nice debugging work tracking this down step by step!
The 0-byte file issue is a classic Redmine upload gotcha. Redmine’s /uploads.json endpoint strictly requires raw binary data in the body (not multipart, not form-encoded). When n8n sends the body using Raw mode, you need to make sure the body value points directly to the binary buffer, not just the binary metadata.
Here’s the exact setup that should work:
HTTP Request node (Upload to Redmine):
Method: POST
URL: https://your-redmine.com/uploads.json
Send Query Parameters: filename = {{ $binary.data.fileName }} (use the actual binary property name, e.g. data)
Input Data Field Name: data (whatever the binary property is called in your previous node output, check the orange label in the node output panel)
The critical part is using n8n Binary File as the body type, NOT Raw. With Raw mode, n8n tries to serialize the binary reference as JSON, which results in an empty or corrupted payload. The n8n Binary File option streams the actual binary buffer directly.
Also double-check the Input Data Field Name matches the orange-labeled property name in the Slack download node output. If it says data, use data. If it says something else, use that exact name.
nguyenthieutoan nailed it. the n8n Binary File body type is the fix, not Raw.
one thing to add — if you’re still getting the “Referenced node doesn’t exist” error on the filename parameter, don’t use an expression there at all for now. just hardcode a filename like test.jpg to isolate the upload issue first. once the file is going through with actual bytes, then go back and wire up the dynamic filename. debugging two things at once is what’s making this harder than it needs to be.
@nguyenthieutoan thanks — and yes, using {{ $binary.data.fileName }} works correctly for me as well, so the filename part is resolved
However, the main issue is still present on my side.
In DownloadFileFromSlack I have:
Response Format: File
Put Output in Field: data
The binary output looks correct in the node output.
But as soon as I configure UploadFilesToRedmine like this:
Body Content Type: n8n Binary File
Input Data Field Name: data (set as a fixed value, not an expression)
The execution immediately fails with: Converting circular structure to JSON
So it seems the issue is triggered specifically when the HTTP Request node tries to process the binary input in n8n Binary File mode, rather than the binary field naming or the Redmine endpoint itself.
At this point, it feels like the binary data is valid up to the node input, but something inside the HTTP Request node execution (queue/worker context) is causing the serialization error.