dify - ✅(Solved) Fix Plugin auto-upgrade silently fails: package never reaches plugin daemon [1 pull requests, 3 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
langgenius/dify#35598Fetched 2026-04-28 06:50:39
View on GitHub
Comments
3
Participants
2
Timeline
6
Reactions
1
Author
Timeline (top)
commented ×3closed ×1cross-referenced ×1labeled ×1

Error Message

  1. The plugin stays on the old version — but worker never reports an error because the daemon endpoint returns 200 and the task ignores the result (_ = manager.upgrade_plugin(...)).

Root Cause

  1. Configure auto-upgrade strategy for a tenant (any mode: ALL / PARTIAL / EXCLUDE).
  2. Wait for check_upgradable_plugin_task to fire (every 15 minutes from beat).
  3. The scheduled job dispatches process_tenant_plugin_autoupgrade_check_task, which iterates upgradable plugins and calls manager.upgrade_plugin(...) directly.
  4. dify-worker logs show: POST .../management/install/upgrade "HTTP/1.1 200 OK" for each plugin — looks successful.
  5. In dify-plugin-daemon logs, however, every upgrade fails with: failed to move plugin to installed bucket: failed to get package file when trying to install plugin to local open /app/storage/plugin_packages/<plugin>:<new-version>@<hash>: no such file or directory.
  6. The plugin stays on the old version — but worker never reports an error because the daemon endpoint returns 200 and the task ignores the result (_ = manager.upgrade_plugin(...)).

Fix Action

Fix / Workaround

  1. Configure auto-upgrade strategy for a tenant (any mode: ALL / PARTIAL / EXCLUDE).
  2. Wait for check_upgradable_plugin_task to fire (every 15 minutes from beat).
  3. The scheduled job dispatches process_tenant_plugin_autoupgrade_check_task, which iterates upgradable plugins and calls manager.upgrade_plugin(...) directly.
  4. dify-worker logs show: POST .../management/install/upgrade "HTTP/1.1 200 OK" for each plugin — looks successful.
  5. In dify-plugin-daemon logs, however, every upgrade fails with: failed to move plugin to installed bucket: failed to get package file when trying to install plugin to local open /app/storage/plugin_packages/<plugin>:<new-version>@<hash>: no such file or directory.
  6. The plugin stays on the old version — but worker never reports an error because the daemon endpoint returns 200 and the task ignores the result (_ = manager.upgrade_plugin(...)).

PR fix notes

PR #35599: fix: download and upload package before invoking upgrade in auto-upgrade task

Description (problem / solution / changelog)

Fixes [#35598]

Summary

The scheduled process_tenant_plugin_autoupgrade_check_task was calling manager.upgrade_plugin(...) directly, which only invokes the daemon's /install/upgrade endpoint. It never downloads the new package from marketplace nor uploads it to the daemon, so the daemon cannot find the package file in its local packageBucket and the upgrade fails silently. The worker is unaware of the failure because the daemon endpoint returns 200 and the task discards the response (_ = manager.upgrade_plugin(...)).

This change routes the auto-upgrade through PluginService.upgrade_plugin_with_marketplace, which is the same code path the console "Upgrade" button uses. It performs fetch_plugin_manifestdownload_plugin_pkgmanager.upload_pkgmanager.upgrade_plugin, ensuring the package is present on the daemon before the upgrade is triggered.

A new unit test file (tests/unit_tests/tasks/test_process_tenant_plugin_autoupgrade_check_task.py) was added with 12 tests covering:

  • The regression itself: assert the task routes through PluginService.upgrade_plugin_with_marketplace and never calls manager.upgrade_plugin directly.
  • All three UpgradeMode variants (ALL / PARTIAL / EXCLUDE) and the non-marketplace source filter.
  • All StrategySetting values (DISABLED / LATEST / FIX_ONLY) including FIX_ONLY's patch-only semantics.
  • Error isolation: a single plugin failing does not block other plugins in the same task run.

Checklist

  • This change does not require documentation updates.
  • I understand that this PR may be closed in case there was no previous discussion or issues.
  • I've added unit tests covering the regression and the existing branches of the task (12 tests, all passing).
  • N/A — no documentation changes.
  • I ran ruff check and ruff format --check on the touched files; both pass.

Changed files

  • api/tasks/process_tenant_plugin_autoupgrade_check_task.py (modified, +5/-5)
  • api/tests/unit_tests/tasks/test_process_tenant_plugin_autoupgrade_check_task.py (added, +289/-0)
RAW_BUFFERClick to expand / collapse

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.13.x

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

  1. Configure auto-upgrade strategy for a tenant (any mode: ALL / PARTIAL / EXCLUDE).
  2. Wait for check_upgradable_plugin_task to fire (every 15 minutes from beat).
  3. The scheduled job dispatches process_tenant_plugin_autoupgrade_check_task, which iterates upgradable plugins and calls manager.upgrade_plugin(...) directly.
  4. dify-worker logs show: POST .../management/install/upgrade "HTTP/1.1 200 OK" for each plugin — looks successful.
  5. In dify-plugin-daemon logs, however, every upgrade fails with: failed to move plugin to installed bucket: failed to get package file when trying to install plugin to local open /app/storage/plugin_packages/<plugin>:<new-version>@<hash>: no such file or directory.
  6. The plugin stays on the old version — but worker never reports an error because the daemon endpoint returns 200 and the task ignores the result (_ = manager.upgrade_plugin(...)).

Root cause (in api/tasks/process_tenant_plugin_autoupgrade_check_task.py):

The task calls manager.upgrade_plugin(...) directly. This only hits daemon's POST /install/upgrade, but never downloads the new package from marketplace nor uploads it to the daemon beforehand. The daemon expects the .difypkg to already exist in its local packageBucket and fails when it cannot find it.

The manual-upgrade path (PluginService.upgrade_plugin_with_marketplace) does the right thing — it calls download_plugin_pkg + manager.upload_pkg before invoking manager.upgrade_plugin. The auto-upgrade path is missing those two steps.

✔️ Expected Behavior

Auto-upgrade should successfully install the new plugin version on the plugin daemon, just like a manual upgrade clicked from the console.

❌ Actual Behavior

  • Worker reports success (HTTP 200) but plugin daemon silently fails in the async installation goroutine.
  • Plugin remains on the old version.
  • The failure is invisible from the worker side — only daemon-side logs reveal it.
  • This affects every auto-upgrade attempt for any tenant; the feature has never worked end-to-end on its own.

extent analysis

TL;DR

The auto-upgrade feature fails because it doesn't download the new plugin package from the marketplace and upload it to the daemon before attempting to upgrade.

Guidance

  • The root cause is in process_tenant_plugin_autoupgrade_check_task.py, where manager.upgrade_plugin(...) is called directly without downloading and uploading the new package.
  • To fix this, the auto-upgrade path should be modified to include the missing steps: download_plugin_pkg and manager.upload_pkg before invoking manager.upgrade_plugin.
  • The manual-upgrade path (PluginService.upgrade_plugin_with_marketplace) can be used as a reference for the correct implementation.
  • The fix should be verified by checking the plugin daemon logs for successful upgrades and ensuring the plugin version is updated correctly.

Example

# Example of the corrected auto-upgrade path
def auto_upgrade_plugin(plugin):
    # Download the new package from the marketplace
    package = download_plugin_pkg(plugin)
    # Upload the package to the daemon
    manager.upload_pkg(package)
    # Upgrade the plugin
    manager.upgrade_plugin(plugin)

Notes

  • The current implementation only affects self-hosted deployments using Docker.
  • The issue is specific to the auto-upgrade feature and does not impact manual upgrades.

Recommendation

Apply workaround: Modify the auto-upgrade path to include the missing steps for downloading and uploading the new plugin package before attempting to upgrade. This will ensure that the plugin daemon has the necessary package to complete the upgrade successfully.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING