[PR #18934] [Observability][Bugfix] Fix expected an instance of Token, got None error in OpenTelemetry #29037

Closed
opened 2026-02-21 20:44:45 -05:00 by yindo · 0 comments
Owner

Original Pull Request: https://github.com/langgenius/dify/pull/18934

State: closed
Merged: Yes


Summary

Fixes #18496.

Previously, the dify_config.ENABLE_OTEL didn't cover the signal method, including init_celery_worker in the ext_otel.py. It turns out that the CeleryInstrumentor will always be enabled in worker mode even if it is turned off in API mode, which causes the error.

2025-04-28 01:23:01,585 INFO [trace.py:128]  Task tasks.document_indexing_task.document_indexing_task[b53522fd-8b37-46ac-b7a0-c960f168b9b8] succeeded in 4.796602125046775s: None
2025-04-28 01:23:01,585 ERROR [__init__.py:156]  Failed to detach context
Traceback (most recent call last):
  File "/VSCodeProject/dify/api/.venv/lib/python3.12/site-packages/opentelemetry/context/__init__.py", line 154, in detach
    _RUNTIME_CONTEXT.detach(token)
  File "/VSCodeProject/dify/api/.venv/lib/python3.12/site-packages/opentelemetry/context/contextvars_context.py", line 50, in detach
    self._current_context.reset(token)  # type: ignore
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: expected an instance of Token, got None

This pull request refactors the OpenTelemetry (OTEL) integration in the codebase by consolidating initialization logic, improving maintainability, and removing a custom patch. The primary changes include removing the ext_otel_patch module, reorganizing OTEL-related imports and functions, and refining initialization processes for Flask, SQLAlchemy, and Celery instrumentation.

Removal of ext_otel_patch:

  • Deleted the ext_otel_patch module, which previously patched OpenTelemetry's context.detach method to handle None tokens gracefully. This patch is no longer necessary. (api/extensions/ext_otel_patch.py, api/extensions/ext_otel_patch.pyL1-L63)
  • Removed references to ext_otel_patch in the initialize_extensions function in api/app_factory.py. ([[1]](diffhunk://#diff-4a41f42da1dee20d447c238eb600571e1e424bfe76bad556de5f6aa20819196dL55), [[2]](diffhunk://#diff-4a41f42da1dee20d447c238eb600571e1e424bfe76bad556de5f6aa20819196dL88))

Consolidation of OTEL Initialization:

  • Moved all OTEL-related imports to a single location within ext_otel.py to improve code organization. ([api/extensions/ext_otel.pyR105-L75](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6R105-L75))
  • Consolidated OTEL initialization logic (e.g., Flask and SQLAlchemy instrumentation, context propagation setup) into ext_otel.py, simplifying the init_app function. ([[1]](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L11-R80), [[2]](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L136-L199))

Improvements to OTEL Instrumentation:

  • Added a new is_enabled function in ext_otel.py to check if OTEL is enabled, ensuring compatibility even when OTEL is disabled. ([api/extensions/ext_otel.pyL136-L199](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L136-L199))
  • Enhanced user-related span attributes by connecting OTEL logic to Flask's user_logged_in and user_loaded_from_request signals. ([api/extensions/ext_otel.pyL11-R80](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L11-R80))

How to test

Set ENABLE_OTEL to False in .env and run the application within both API and worker mode.
Expected behavior: OTEL instrumentation should be fully disabled, and the error should not occur.

Screenshots

N/A

Checklist

Important

Please review the checklist below before submitting your pull request.

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran dev/reformat(backend) and cd web && npx lint-staged(frontend) to appease the lint gods
**Original Pull Request:** https://github.com/langgenius/dify/pull/18934 **State:** closed **Merged:** Yes --- # Summary Fixes #18496. Previously, the dify_config.ENABLE_OTEL didn't cover the signal method, including init_celery_worker in the ext_otel.py. It turns out that the CeleryInstrumentor will always be enabled in worker mode even if it is turned off in API mode, which causes the error. ``` 2025-04-28 01:23:01,585 INFO [trace.py:128] Task tasks.document_indexing_task.document_indexing_task[b53522fd-8b37-46ac-b7a0-c960f168b9b8] succeeded in 4.796602125046775s: None 2025-04-28 01:23:01,585 ERROR [__init__.py:156] Failed to detach context Traceback (most recent call last): File "/VSCodeProject/dify/api/.venv/lib/python3.12/site-packages/opentelemetry/context/__init__.py", line 154, in detach _RUNTIME_CONTEXT.detach(token) File "/VSCodeProject/dify/api/.venv/lib/python3.12/site-packages/opentelemetry/context/contextvars_context.py", line 50, in detach self._current_context.reset(token) # type: ignore ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ TypeError: expected an instance of Token, got None ``` This pull request refactors the OpenTelemetry (OTEL) integration in the codebase by consolidating initialization logic, improving maintainability, and removing a custom patch. The primary changes include removing the `ext_otel_patch` module, reorganizing OTEL-related imports and functions, and refining initialization processes for Flask, SQLAlchemy, and Celery instrumentation. ### Removal of `ext_otel_patch`: * Deleted the `ext_otel_patch` module, which previously patched OpenTelemetry's `context.detach` method to handle `None` tokens gracefully. This patch is no longer necessary. (`api/extensions/ext_otel_patch.py`, [api/extensions/ext_otel_patch.pyL1-L63](diffhunk://#diff-3abd64e2555b9471771b0b3d863a6c3487f1a6f6f7e19558d0ed93abbdc36639L1-L63)) * Removed references to `ext_otel_patch` in the `initialize_extensions` function in `api/app_factory.py`. (`[[1]](diffhunk://#diff-4a41f42da1dee20d447c238eb600571e1e424bfe76bad556de5f6aa20819196dL55)`, `[[2]](diffhunk://#diff-4a41f42da1dee20d447c238eb600571e1e424bfe76bad556de5f6aa20819196dL88)`) ### Consolidation of OTEL Initialization: * Moved all OTEL-related imports to a single location within `ext_otel.py` to improve code organization. (`[api/extensions/ext_otel.pyR105-L75](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6R105-L75)`) * Consolidated OTEL initialization logic (e.g., Flask and SQLAlchemy instrumentation, context propagation setup) into `ext_otel.py`, simplifying the `init_app` function. (`[[1]](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L11-R80)`, `[[2]](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L136-L199)`) ### Improvements to OTEL Instrumentation: * Added a new `is_enabled` function in `ext_otel.py` to check if OTEL is enabled, ensuring compatibility even when OTEL is disabled. (`[api/extensions/ext_otel.pyL136-L199](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L136-L199)`) * Enhanced user-related span attributes by connecting OTEL logic to Flask's `user_logged_in` and `user_loaded_from_request` signals. (`[api/extensions/ext_otel.pyL11-R80](diffhunk://#diff-d9b99e6e386de2f18f686daf1e6fcb87ca02c20900826cbdc5892a5e81f362b6L11-R80)`) # How to test Set `ENABLE_OTEL` to `False` in `.env` and run the application within both API and worker mode. Expected behavior: OTEL instrumentation should be fully disabled, and the error should not occur. # Screenshots N/A # Checklist > [!IMPORTANT] > Please review the checklist below before submitting your pull request. - [ ] This change requires a documentation update, included: [Dify Document](https://github.com/langgenius/dify-docs) - [x] I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!) - [x] I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change. - [x] I've updated the documentation accordingly. - [x] I ran `dev/reformat`(backend) and `cd web && npx lint-staged`(frontend) to appease the lint gods
yindo added the pull-request label 2026-02-21 20:44:45 -05:00
yindo closed this issue 2026-02-21 20:44:45 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#29037