ValueError: Illegal header name b'' #20103

Closed
opened 2026-02-21 20:05:50 -05:00 by yindo · 9 comments
Owner

Originally created by @Aurora-1412 on GitHub (Nov 3, 2025).

Self Checks

  • I have read the Contributing Guide and Language Policy.
  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report, otherwise it will be closed.
  • 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
  • Please do not modify this template :) and fill in all the required fields.

Dify version

1.9.1

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

  1. deploy ragflow mcp using docker as shown in :https://ragflow.com.cn/docs/dev/launch_mcp_server
  2. click "add mcp server"
  3. try different url and header (all of them lead to one same error: ValueError: Illegal header name b'')
    That is , whether using http://localhost:9382/mcp/
    or http://localhost:9382/sse or http://host.docker.internal:9382/mcp/ or http://host.docker.internal:9382/sse
    , adding Authorization Bearer or not, it is always: ValueError: Illegal header name b''

✔️ Expected Behavior

successfully add an mcp as tutorials in the Internet

Actual Behavior

Total error log is like:
2025-11-03 14:09:55.830 ERROR [ThreadPoolExecutor-57_0] [base_session.py:382] - Error in message processing loop Traceback (most recent call last): File "/app/api/core/mcp/session/base_session.py", line 337, in _receive_loop self._handle_incoming(message) File "/app/api/core/mcp/session/client_session.py", line 355, in _handle_incoming self._message_handler(req) File "/app/api/core/mcp/session/client_session.py", line 45, in _default_message_handler raise ValueError(str(message)) ValueError: Illegal header name b''

Exception ignored in: <generator object streamablehttp_client at 0x7ff9b41920c0> Traceback (most recent call last): File "/app/api/core/mcp/client/streamable_client.py", line 437, in streamablehttp_client with ThreadPoolExecutor(max_workers=2) as executor: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/concurrent/futures/_base.py", line 647, in exit self.shutdown(wait=True) File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 239, in shutdown t.join() File "/usr/local/lib/python3.12/threading.py", line 1149, in join self._wait_for_tstate_lock() File "/usr/local/lib/python3.12/threading.py", line 1169, in _wait_for_tstate_lock if lock.acquire(block, timeout): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/gevent/thread.py", line 302, in acquire acquired = BoundedSemaphore.acquire(self, blocking, timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "src/gevent/_semaphore.py", line 184, in gevent._gevent_c_semaphore.Semaphore.acquire File "src/gevent/_semaphore.py", line 253, in gevent._gevent_c_semaphore.Semaphore.acquire File "src/gevent/_abstract_linkable.py", line 529, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait File "src/gevent/_abstract_linkable.py", line 495, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core File "src/gevent/_abstract_linkable.py", line 498, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core File "src/gevent/_abstract_linkable.py", line 450, in gevent._gevent_c_abstract_linkable.AbstractLinkable._AbstractLinkable__wait_to_be_notified File "src/gevent/_abstract_linkable.py", line 459, in gevent._gevent_c_abstract_linkable.AbstractLinkable._switch_to_hub File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch File "src/gevent/_greenlet_primitives.py", line 64, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch File "src/gevent/_greenlet_primitives.py", line 67, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch_out File "src/gevent/_greenlet_primitives.py", line 68, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch_out gevent.exceptions.BlockingSwitchOutError: Impossible to call blocking function in the event loop callback

Originally created by @Aurora-1412 on GitHub (Nov 3, 2025). ### Self Checks - [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542). - [x] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [x] I confirm that I am using English to submit this report, otherwise it will be closed. - [x] 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :) - [x] Please do not modify this template :) and fill in all the required fields. ### Dify version 1.9.1 ### Cloud or Self Hosted Self Hosted (Docker) ### Steps to reproduce 1. deploy ragflow mcp using docker as shown in :https://ragflow.com.cn/docs/dev/launch_mcp_server 2. click "add mcp server" 3. try different url and header (all of them lead to one same error: ValueError: Illegal header name b'') That is , whether using http://localhost:9382/mcp/ or http://localhost:9382/sse or http://host.docker.internal:9382/mcp/ or http://host.docker.internal:9382/sse , adding Authorization Bearer <ragflow-api-key> or not, it is always: ValueError: Illegal header name b'' ### ✔️ Expected Behavior successfully add an mcp as tutorials in the Internet ### ❌ Actual Behavior Total error log is like: 2025-11-03 14:09:55.830 ERROR [ThreadPoolExecutor-57_0] [base_session.py:382] - Error in message processing loop Traceback (most recent call last): File "/app/api/core/mcp/session/base_session.py", line 337, in _receive_loop self._handle_incoming(message) File "/app/api/core/mcp/session/client_session.py", line 355, in _handle_incoming self._message_handler(req) File "/app/api/core/mcp/session/client_session.py", line 45, in _default_message_handler raise ValueError(str(message)) ValueError: Illegal header name b'' Exception ignored in: <generator object streamablehttp_client at 0x7ff9b41920c0> Traceback (most recent call last): File "/app/api/core/mcp/client/streamable_client.py", line 437, in streamablehttp_client with ThreadPoolExecutor(max_workers=2) as executor: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/concurrent/futures/_base.py", line 647, in __exit__ self.shutdown(wait=True) File "/usr/local/lib/python3.12/concurrent/futures/thread.py", line 239, in shutdown t.join() File "/usr/local/lib/python3.12/threading.py", line 1149, in join self._wait_for_tstate_lock() File "/usr/local/lib/python3.12/threading.py", line 1169, in _wait_for_tstate_lock if lock.acquire(block, timeout): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/gevent/thread.py", line 302, in acquire acquired = BoundedSemaphore.acquire(self, blocking, timeout) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "src/gevent/_semaphore.py", line 184, in gevent._gevent_c_semaphore.Semaphore.acquire File "src/gevent/_semaphore.py", line 253, in gevent._gevent_c_semaphore.Semaphore.acquire File "src/gevent/_abstract_linkable.py", line 529, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait File "src/gevent/_abstract_linkable.py", line 495, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core File "src/gevent/_abstract_linkable.py", line 498, in gevent._gevent_c_abstract_linkable.AbstractLinkable._wait_core File "src/gevent/_abstract_linkable.py", line 450, in gevent._gevent_c_abstract_linkable.AbstractLinkable._AbstractLinkable__wait_to_be_notified File "src/gevent/_abstract_linkable.py", line 459, in gevent._gevent_c_abstract_linkable.AbstractLinkable._switch_to_hub File "src/gevent/_greenlet_primitives.py", line 61, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch File "src/gevent/_greenlet_primitives.py", line 64, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch File "src/gevent/_greenlet_primitives.py", line 67, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch_out File "src/gevent/_greenlet_primitives.py", line 68, in gevent._gevent_c_greenlet_primitives.SwitchOutGreenletWithLoop.switch_out gevent.exceptions.BlockingSwitchOutError: Impossible to call blocking function in the event loop callback
yindo added the 🐞 bug label 2026-02-21 20:05:50 -05:00
yindo closed this issue 2026-02-21 20:05:51 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Nov 3, 2025):

Hi @Aurora-1412! I'm Dosu and I’m helping the dify team.

This error happens because an empty string is being used as an HTTP header name when Dify tries to connect to the MCP server. Python's HTTP libraries (like httpx) do not allow empty header names, so if your MCP provider configuration includes a headers field with an empty key (for example, { "": "some_value" }), it will trigger this error. This can occur even if you don't explicitly set headers, depending on how the frontend or API payload is structured.

To fix this, check your MCP server configuration and make sure there are no empty keys in the headers dictionary—every header must have a non-empty string as its key. If you are using the API or UI to add the MCP server, double-check the headers field for any accidental empty keys or values. If you are not using custom headers, try removing the headers field entirely from your configuration.

This issue is not related to the URL or authorization token itself, but specifically to malformed headers in the MCP provider config. Recent Dify updates have improved header validation, but in 1.9.1, you need to ensure your config is clean to avoid this error. For more details, see the relevant code and discussion here.

If you continue to see this error after cleaning up your headers, make sure your database migrations are up to date and that your MCP provider config does not include any blank or malformed fields.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 3, 2025): <!-- Greeting --> Hi @Aurora-1412! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the dify team. <!-- Answer --> This error happens because an empty string is being used as an HTTP header name when Dify tries to connect to the MCP server. Python's HTTP libraries (like httpx) do not allow empty header names, so if your MCP provider configuration includes a headers field with an empty key (for example, `{ "": "some_value" }`), it will trigger this error. This can occur even if you don't explicitly set headers, depending on how the frontend or API payload is structured. To fix this, check your MCP server configuration and make sure there are no empty keys in the headers dictionary—every header must have a non-empty string as its key. If you are using the API or UI to add the MCP server, double-check the headers field for any accidental empty keys or values. If you are not using custom headers, try removing the headers field entirely from your configuration. This issue is not related to the URL or authorization token itself, but specifically to malformed headers in the MCP provider config. Recent Dify updates have improved header validation, but in 1.9.1, you need to ensure your config is clean to avoid this error. For more details, see the relevant code and discussion [here](https://github.com/langgenius/dify/blob/11f2f9510366e88bdcd3badf9b54d8b8a7228b5c/api/core/mcp/client/streamable_client.py#L79-L481). If you continue to see this error after cleaning up your headers, make sure your database migrations are up to date and that your MCP provider config does not include any blank or malformed fields. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/c316e6ed-64bd-464c-b13f-4b198be86710?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/c316e6ed-64bd-464c-b13f-4b198be86710?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/c316e6ed-64bd-464c-b13f-4b198be86710?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/c316e6ed-64bd-464c-b13f-4b198be86710?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/c316e6ed-64bd-464c-b13f-4b198be86710?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/c316e6ed-64bd-464c-b13f-4b198be86710?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/c316e6ed-64bd-464c-b13f-4b198be86710?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/27785)
Author
Owner

@dosubot[bot] commented on GitHub (Nov 3, 2025):

Hi @Aurora-1412! I'm Dosu and I’m helping the dify team.

This error happens because Dify does not validate MCP provider header names, so if your configuration includes a header with an empty key (even by accident), it gets passed all the way to the HTTP client, which then raises ValueError: Illegal header name b'' when trying to send the request. This can occur if the headers field in your MCP provider config is present but contains an empty string as a key, or if the frontend/UI sends malformed headers (like { "": "somevalue" }) to the backend.

To fix this, double-check your MCP provider configuration and make sure all custom headers are valid key-value pairs with non-empty names and values. Remove any accidental empty keys. If you’re editing JSON directly, look for lines like "": "something" and delete them.

Recent Dify updates have improved header handling and validation, so upgrading to the latest version may also help prevent this issue in the future. If you’re running database migrations, make sure all MCP-related migrations (especially those adding the headers field) have been applied, as missing migrations can cause related backend errors as well. More details and troubleshooting steps are discussed here.

If you’re running Dify in Docker, also make sure your MCP service URL is reachable from inside the container (avoid localhost or 127.0.0.1 unless your MCP service is running in the same container; use host.docker.internal or the host’s LAN IP instead) and that your MCP service URL ends with a / to avoid redirect issues.

If you clean up your headers and still see the error, check your backend logs for any other clues about malformed configuration.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 3, 2025): <!-- Greeting --> Hi @Aurora-1412! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the dify team. <!-- Answer --> This error happens because Dify does not validate MCP provider header names, so if your configuration includes a header with an empty key (even by accident), it gets passed all the way to the HTTP client, which then raises `ValueError: Illegal header name b''` when trying to send the request. This can occur if the headers field in your MCP provider config is present but contains an empty string as a key, or if the frontend/UI sends malformed headers (like `{ "": "somevalue" }`) to the backend. To fix this, double-check your MCP provider configuration and make sure all custom headers are valid key-value pairs with non-empty names and values. Remove any accidental empty keys. If you’re editing JSON directly, look for lines like `"": "something"` and delete them. Recent Dify updates have improved header handling and validation, so upgrading to the latest version may also help prevent this issue in the future. If you’re running database migrations, make sure all MCP-related migrations (especially those adding the `headers` field) have been applied, as missing migrations can cause related backend errors as well. More details and troubleshooting steps are discussed [here](https://github.com/langgenius/dify/discussions/25519). If you’re running Dify in Docker, also make sure your MCP service URL is reachable from inside the container (avoid `localhost` or `127.0.0.1` unless your MCP service is running in the same container; use `host.docker.internal` or the host’s LAN IP instead) and that your MCP service URL ends with a `/` to avoid redirect issues. If you clean up your headers and still see the error, check your backend logs for any other clues about malformed configuration. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/cfc774ad-a5b1-49c1-b66e-1d46b63984db?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/cfc774ad-a5b1-49c1-b66e-1d46b63984db?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/cfc774ad-a5b1-49c1-b66e-1d46b63984db?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/cfc774ad-a5b1-49c1-b66e-1d46b63984db?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/cfc774ad-a5b1-49c1-b66e-1d46b63984db?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/cfc774ad-a5b1-49c1-b66e-1d46b63984db?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/cfc774ad-a5b1-49c1-b66e-1d46b63984db?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/27785)
Author
Owner

@Aurora-1412 commented on GitHub (Nov 3, 2025):

@dosu
I'm sure there's no empty key-value pairs. By the way, does Dify only support http mcp? (cannot use sse)

@Aurora-1412 commented on GitHub (Nov 3, 2025): @dosu I'm sure there's no empty key-value pairs. By the way, does Dify only support http mcp? (cannot use sse)
Author
Owner

@dosubot[bot] commented on GitHub (Nov 3, 2025):

Dify supports both HTTP and SSE for MCP connections. You can use an SSE endpoint (like /mcp/sse) for MCP server registration and communication—Dify will connect to this endpoint and expects it to emit an endpoint event in standard SSE wire format so it can discover your MCP tool invocation URL. The MCP server should also implement a JSONRPC protocol on the main endpoint (e.g., /ask) for actual tool calls. For details and a minimal FastAPI example, see this discussion and here.

If you’re seeing connection errors with SSE, double-check your endpoint implementation and network setup. Dify’s codebase includes native support for SSE transport in MCP clients (code reference), so you do not need a plugin for SSE support.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 3, 2025): <!-- Answer --> Dify supports both HTTP and SSE for MCP connections. You can use an SSE endpoint (like `/mcp/sse`) for MCP server registration and communication—Dify will connect to this endpoint and expects it to emit an `endpoint` event in standard SSE wire format so it can discover your MCP tool invocation URL. The MCP server should also implement a JSONRPC protocol on the main endpoint (e.g., `/ask`) for actual tool calls. For details and a minimal FastAPI example, see [this discussion](https://github.com/langgenius/dify/discussions/23520) and [here](https://github.com/langgenius/dify/discussions/26545). If you’re seeing connection errors with SSE, double-check your endpoint implementation and network setup. Dify’s codebase includes native support for SSE transport in MCP clients ([code reference](https://github.com/langgenius/dify/pull/23984)), so you do not need a plugin for SSE support. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/f7234640-5879-4946-adef-f5dc451f6602?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/f7234640-5879-4946-adef-f5dc451f6602?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/f7234640-5879-4946-adef-f5dc451f6602?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/f7234640-5879-4946-adef-f5dc451f6602?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/f7234640-5879-4946-adef-f5dc451f6602?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/f7234640-5879-4946-adef-f5dc451f6602?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/f7234640-5879-4946-adef-f5dc451f6602?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/27785)
Author
Owner

@Aurora-1412 commented on GitHub (Nov 3, 2025):

@dosubot
I cannot use etheir sse or mcp. They lead to same error: 2025-11-04 01:59:05.969 ERROR [Dummy-450] [app.py:875] - Exception on /console/api/workspaces/current/tool-provider/mcp [PUT]
Traceback (most recent call last):
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 72, in map_httpcore_exceptions
yield
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 236, in handle_request
resp = self._pool.handle_request(req)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py", line 256, in handle_request
raise exc from None
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py", line 236, in handle_request
response = connection.handle_request(
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http_proxy.py", line 206, in handle_request
return self._connection.handle_request(proxy_request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/connection.py", line 103, in handle_request
return self._connection.handle_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http11.py", line 136, in handle_request
raise exc
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http11.py", line 86, in handle_request
self._send_request_headers(**kwargs)
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http11.py", line 144, in _send_request_headers
with map_exceptions({h11.LocalProtocolError: LocalProtocolError}):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/contextlib.py", line 158, in exit
self.gen.throw(value)
File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions
raise to_exc(exc) from exc
httpcore.LocalProtocolError: Illegal header name b''

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
File "/app/api/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/flask_restx/api.py", line 402, in wrapper
resp = resource(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/flask/views.py", line 110, in view
return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return]
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/flask_restx/resource.py", line 41, in dispatch_request
resp = meth(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/app/api/controllers/console/wraps.py", line 215, in decorated
return view(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/app/api/libs/login.py", line 62, in decorated_view
return current_app.ensure_sync(func)(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/controllers/console/wraps.py", line 37, in decorated
return view(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/app/api/controllers/console/workspace/tool_providers.py", line 910, in put
MCPToolManageService.update_mcp_provider(
File "/app/api/services/tools/mcp_tools_manage_service.py", line 238, in update_mcp_provider
reconnect_result = cls._re_connect_mcp_provider(server_url, provider_id, tenant_id)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/services/tools/mcp_tools_manage_service.py", line 329, in _re_connect_mcp_provider
with MCPClient(
^^^^^^^^^^
File "/app/api/core/mcp/mcp_client.py", line 58, in enter
self._initialize()
File "/app/api/core/mcp/mcp_client.py", line 79, in _initialize
self.connect_server(client_factory, method_name)
File "/app/api/core/mcp/mcp_client.py", line 113, in connect_server
streams = self._exit_stack.enter_context(self._streams_context)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/contextlib.py", line 526, in enter_context
result = _enter(cm)
^^^^^^^^^^
File "/usr/local/lib/python3.12/contextlib.py", line 137, in enter
return next(self.gen)
^^^^^^^^^^^^^^
File "/app/api/core/mcp/client/sse_client.py", line 282, in sse_client
with ssrf_proxy_sse_connect(
^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/contextlib.py", line 137, in enter
return next(self.gen)
^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpx_sse/_api.py", line 59, in connect_sse
with client.stream(method, url, headers=headers, **kwargs) as response:
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/contextlib.py", line 137, in enter
return next(self.gen)
^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 880, in stream
response = self.send(
^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 926, in send
response = self._send_handling_auth(
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 954, in _send_handling_auth
response = self._send_handling_redirects(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 991, in _send_handling_redirects
response = self._send_single_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 1027, in _send_single_request
response = transport.handle_request(request)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 235, in handle_request
with map_httpcore_exceptions():
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/usr/local/lib/python3.12/contextlib.py", line 158, in exit
self.gen.throw(value)
File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 89, in map_httpcore_exceptions
raise mapped_exc(message) from exc
httpx.LocalProtocolError: Illegal header name b''

I'm sure there's no empty head. My configuration is below:

Image
@Aurora-1412 commented on GitHub (Nov 3, 2025): @dosubot I cannot use etheir sse or mcp. They lead to same error: 2025-11-04 01:59:05.969 ERROR [Dummy-450] [app.py:875] - Exception on /console/api/workspaces/current/tool-provider/mcp [PUT] Traceback (most recent call last): File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 72, in map_httpcore_exceptions yield File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 236, in handle_request resp = self._pool.handle_request(req) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py", line 256, in handle_request raise exc from None File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/connection_pool.py", line 236, in handle_request response = connection.handle_request( ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http_proxy.py", line 206, in handle_request return self._connection.handle_request(proxy_request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/connection.py", line 103, in handle_request return self._connection.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http11.py", line 136, in handle_request raise exc File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http11.py", line 86, in handle_request self._send_request_headers(**kwargs) File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_sync/http11.py", line 144, in _send_request_headers with map_exceptions({h11.LocalProtocolError: LocalProtocolError}): ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ self.gen.throw(value) File "/app/api/.venv/lib/python3.12/site-packages/httpcore/_exceptions.py", line 14, in map_exceptions raise to_exc(exc) from exc httpcore.LocalProtocolError: Illegal header name b'' The above exception was the direct cause of the following exception: Traceback (most recent call last): File "/app/api/.venv/lib/python3.12/site-packages/flask/app.py", line 917, in full_dispatch_request rv = self.dispatch_request() ^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/flask/app.py", line 902, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/flask_restx/api.py", line 402, in wrapper resp = resource(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/flask/views.py", line 110, in view return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/flask_restx/resource.py", line 41, in dispatch_request resp = meth(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/app/api/controllers/console/wraps.py", line 215, in decorated return view(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/app/api/libs/login.py", line 62, in decorated_view return current_app.ensure_sync(func)(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/controllers/console/wraps.py", line 37, in decorated return view(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^ File "/app/api/controllers/console/workspace/tool_providers.py", line 910, in put MCPToolManageService.update_mcp_provider( File "/app/api/services/tools/mcp_tools_manage_service.py", line 238, in update_mcp_provider reconnect_result = cls._re_connect_mcp_provider(server_url, provider_id, tenant_id) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/services/tools/mcp_tools_manage_service.py", line 329, in _re_connect_mcp_provider with MCPClient( ^^^^^^^^^^ File "/app/api/core/mcp/mcp_client.py", line 58, in __enter__ self._initialize() File "/app/api/core/mcp/mcp_client.py", line 79, in _initialize self.connect_server(client_factory, method_name) File "/app/api/core/mcp/mcp_client.py", line 113, in connect_server streams = self._exit_stack.enter_context(self._streams_context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/contextlib.py", line 526, in enter_context result = _enter(cm) ^^^^^^^^^^ File "/usr/local/lib/python3.12/contextlib.py", line 137, in __enter__ return next(self.gen) ^^^^^^^^^^^^^^ File "/app/api/core/mcp/client/sse_client.py", line 282, in sse_client with ssrf_proxy_sse_connect( ^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/contextlib.py", line 137, in __enter__ return next(self.gen) ^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpx_sse/_api.py", line 59, in connect_sse with client.stream(method, url, headers=headers, **kwargs) as response: ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/contextlib.py", line 137, in __enter__ return next(self.gen) ^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 880, in stream response = self.send( ^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 926, in send response = self._send_handling_auth( ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 954, in _send_handling_auth response = self._send_handling_redirects( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 991, in _send_handling_redirects response = self._send_single_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpx/_client.py", line 1027, in _send_single_request response = transport.handle_request(request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 235, in handle_request with map_httpcore_exceptions(): ^^^^^^^^^^^^^^^^^^^^^^^^^ File "/usr/local/lib/python3.12/contextlib.py", line 158, in __exit__ self.gen.throw(value) File "/app/api/.venv/lib/python3.12/site-packages/httpx/_transports/default.py", line 89, in map_httpcore_exceptions raise mapped_exc(message) from exc httpx.LocalProtocolError: Illegal header name b'' I'm sure there's no empty head. My configuration is below: <img width="523" height="756" alt="Image" src="https://github.com/user-attachments/assets/37e062c9-eb4e-4452-858b-0580237504de" />
Author
Owner

@dosubot[bot] commented on GitHub (Nov 3, 2025):

This error is almost always caused by an empty string being used as a header name somewhere in the MCP provider configuration. Even if your UI looks correct, Dify's backend does not validate header names for emptiness—so if the frontend or API ever submits a headers dictionary with an empty key (like { "": "something" }), it will be stored and later passed to httpx, which then raises Illegal header name b'' when making the request. This can happen if, for example, you add a row in the custom headers table but leave the key blank and save, or if there's a serialization bug in the UI that sends an empty key.

To fix this, double-check your MCP provider's custom headers in the UI: remove any rows with a blank key, and make sure there are no invisible or whitespace-only keys. If you have direct database access, check the encrypted_headers field in the tool_mcp_providers table for any entries with an empty string as a key and remove them. Dify 1.9.1 does not filter these out automatically.

If you are certain your headers are clean but still see this error, try deleting and recreating the MCP provider from scratch, being careful not to add any blank header rows. If the problem persists, there may be a stale or corrupted entry in the database from a previous attempt.

Dify supports both HTTP and SSE for MCP, and this error is not related to the transport type or network setup, but specifically to malformed headers in the MCP provider config. A future version of Dify may add stricter validation to prevent this at the UI or API layer.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 3, 2025): <!-- Answer --> This error is almost always caused by an empty string being used as a header name somewhere in the MCP provider configuration. Even if your UI looks correct, Dify's backend does not validate header names for emptiness—so if the frontend or API ever submits a headers dictionary with an empty key (like `{ "": "something" }`), it will be stored and later passed to httpx, which then raises `Illegal header name b''` when making the request. This can happen if, for example, you add a row in the custom headers table but leave the key blank and save, or if there's a serialization bug in the UI that sends an empty key. To fix this, double-check your MCP provider's custom headers in the UI: remove any rows with a blank key, and make sure there are no invisible or whitespace-only keys. If you have direct database access, check the `encrypted_headers` field in the `tool_mcp_providers` table for any entries with an empty string as a key and remove them. Dify 1.9.1 does not filter these out automatically. If you are certain your headers are clean but still see this error, try deleting and recreating the MCP provider from scratch, being careful not to add any blank header rows. If the problem persists, there may be a stale or corrupted entry in the database from a previous attempt. Dify supports both HTTP and SSE for MCP, and this error is not related to the transport type or network setup, but specifically to malformed headers in the MCP provider config. A future version of Dify may add stricter validation to prevent this at the UI or API layer. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/cfd79f5e-ba9b-4d33-9a0f-e342b678a969?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/cfd79f5e-ba9b-4d33-9a0f-e342b678a969?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/cfd79f5e-ba9b-4d33-9a0f-e342b678a969?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/cfd79f5e-ba9b-4d33-9a0f-e342b678a969?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/cfd79f5e-ba9b-4d33-9a0f-e342b678a969?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/cfd79f5e-ba9b-4d33-9a0f-e342b678a969?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/cfd79f5e-ba9b-4d33-9a0f-e342b678a969?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/27785)
Author
Owner

@Aurora-1412 commented on GitHub (Nov 3, 2025):

@dosu
In dify-db-1 container, execute SELECT id, name, server_url, encrypted_headers FROM tool_mcp_providers; but find nothing:
id | name | server_url | encrypted_headers
----+------+------------+-------------------
(0 rows)

curl -v -H "Accept: text/event-stream" http://127.0.0.1:9382/mcp/ returns status code 200
I'm still confused about how the error occurs.

@Aurora-1412 commented on GitHub (Nov 3, 2025): @dosu In dify-db-1 container, execute `SELECT id, name, server_url, encrypted_headers FROM tool_mcp_providers;` but find nothing: id | name | server_url | encrypted_headers ----+------+------------+------------------- (0 rows) `curl -v -H "Accept: text/event-stream" http://127.0.0.1:9382/mcp/` returns status code 200 I'm still confused about how the error occurs.
Author
Owner

@dosubot[bot] commented on GitHub (Nov 3, 2025):

This error can happen even when your tool_mcp_providers table is empty because the malformed headers are sent in the initial API request when you try to add or update an MCP provider—not after the provider is saved. If the frontend or API payload includes a headers dictionary with an empty key (even if you don't see it in the UI), Dify's backend passes it directly to the HTTP client, which then raises the "Illegal header name b''" error before any database record is created or updated. This is a known issue in Dify v1.9.1, where header validation is loose and invisible or residual empty keys can sneak into the payload during registration or update attempts citation.

Your successful curl shows the MCP server is reachable, so the problem is not network-related. To debug further, use your browser's developer tools (Network tab) to inspect the actual payload sent when you submit the MCP provider form—look for any empty or whitespace-only keys in the headers field. If you find any, remove them and try again. If the UI is generating these accidentally, you may need to clear out all custom headers and re-enter them, or upgrade to a newer Dify version where this bug is fixed citation.

In summary: the error is triggered by the request payload, not by anything stored in the database, and can occur even if no MCP providers exist yet.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other  Chat with Dosu Join Discord Share on X

@dosubot[bot] commented on GitHub (Nov 3, 2025): <!-- Answer --> This error can happen even when your tool_mcp_providers table is empty because the malformed headers are sent in the initial API request when you try to add or update an MCP provider—not after the provider is saved. If the frontend or API payload includes a headers dictionary with an empty key (even if you don't see it in the UI), Dify's backend passes it directly to the HTTP client, which then raises the "Illegal header name b''" error before any database record is created or updated. This is a known issue in Dify v1.9.1, where header validation is loose and invisible or residual empty keys can sneak into the payload during registration or update attempts [citation](https://github.com/langgenius/dify/issues/26727). Your successful curl shows the MCP server is reachable, so the problem is not network-related. To debug further, use your browser's developer tools (Network tab) to inspect the actual payload sent when you submit the MCP provider form—look for any empty or whitespace-only keys in the headers field. If you find any, remove them and try again. If the UI is generating these accidentally, you may need to clear out all custom headers and re-enter them, or upgrade to a newer Dify version where this bug is fixed [citation](https://github.com/langgenius/dify/pull/25766). In summary: the error is triggered by the request payload, not by anything stored in the database, and can occur even if no MCP providers exist yet. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/ddd2aa47-8d44-4689-8e7c-b25fa281dc28?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/ddd2aa47-8d44-4689-8e7c-b25fa281dc28?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/ddd2aa47-8d44-4689-8e7c-b25fa281dc28?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/ddd2aa47-8d44-4689-8e7c-b25fa281dc28?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/ddd2aa47-8d44-4689-8e7c-b25fa281dc28?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/ddd2aa47-8d44-4689-8e7c-b25fa281dc28?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/ddd2aa47-8d44-4689-8e7c-b25fa281dc28?feedback_type=other)</sup>&nbsp;&nbsp;[![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/27785)
Author
Owner

@Aurora-1412 commented on GitHub (Nov 4, 2025):

After using 127.0.0.1 rather than host.docker.internal, and using /sse rather than /mcp or /mcp/sse, it is ok.

@Aurora-1412 commented on GitHub (Nov 4, 2025): After using 127.0.0.1 rather than host.docker.internal, and using /sse rather than /mcp or /mcp/sse, it is ok.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#20103