Skip to content

fix: re-download .difypkg when package file missing from disk during plugin upgrade#34490

Open
euxx wants to merge 3 commits into
langgenius:mainfrom
euxx:fix/upgrade-plugin-redownload-missing-pkg
Open

fix: re-download .difypkg when package file missing from disk during plugin upgrade#34490
euxx wants to merge 3 commits into
langgenius:mainfrom
euxx:fix/upgrade-plugin-redownload-missing-pkg

Conversation

@euxx

@euxx euxx commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes langgenius/dify-plugin-daemon#673

Plugin upgrades (both manual UI and auto-upgrade task) fail with failed to get package file when .difypkg files are missing from disk but DB/Redis declarations still exist. This commonly occurs after PVC recreation or storage migration in Kubernetes.

Problem

Two code paths skip re-downloading when they shouldn't:

  1. upgrade_plugin_with_marketplace()fetch_plugin_manifest() only checks the DB declaration, not the actual file on disk. When the file is gone, the download is skipped and the daemon fails.

  2. process_tenant_plugin_autoupgrade_check_task() — calls upgrade_plugin() directly with no file existence check at all.

Fix

Add decode_plugin_from_identifier() calls to both paths to verify the .difypkg file actually exists on disk before proceeding. If the decode fails (file missing), re-download from the Marketplace.

Changes

  • api/services/plugin/plugin_service.py: Add decode_plugin_from_identifier() after fetch_plugin_manifest() in upgrade_plugin_with_marketplace()
  • api/tasks/process_tenant_plugin_autoupgrade_check_task.py: Add decode check + download fallback before upgrade_plugin() call
  • Tests: 8 unit tests covering both code paths (pkg exists, pkg missing, version match skip)

Screenshots

N/A — backend-only change, no UI modifications.

Checklist

  • 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 make lint and make type-check (backend) and cd web && npx lint-staged (frontend) to appease the lint gods

euxx added 3 commits April 2, 2026 19:20
…in_with_marketplace

fetch_plugin_manifest only checks the DB/Redis for a PluginDeclaration record
and does not verify that the actual .difypkg file exists on disk. If the file
was lost (e.g. PVC recreation) while the declaration remained in DB, the upgrade
would skip re-downloading and the Go daemon would fail with:
  "failed to get package file ... no such file or directory"

Fix: also call decode_plugin_from_identifier (which calls manager.GetPackage()
and reads the actual disk file) in the try block, mirroring the pattern already
used correctly in fetch_marketplace_pkg.
The auto-upgrade task directly calls manager.upgrade_plugin() without
checking if the .difypkg file exists on disk. When the file is lost
(e.g. PVC recreation) but the DB record remains, the Go daemon fails with:
  'failed to get package file ... no such file or directory'

Fix: call decode_plugin_from_identifier to verify the package file exists
before upgrading. If it's missing, download from the marketplace and upload
to the daemon first. This is the same pattern applied in plugin_service.py
for the manual upgrade path.
- Update TestUpgradePluginWithMarketplace.test_skips_download to verify
  decode_plugin_from_identifier is called after fetch_plugin_manifest
- Add test_redownloads_when_pkg_file_missing: manifest exists in DB but
  .difypkg file missing on disk triggers re-download from marketplace
- New test file for auto-upgrade celery task covering:
  - pkg file exists on disk -> no download
  - pkg file missing -> download + upload before upgrade
  - version matches -> no upgrade attempted
@dosubot dosubot Bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Apr 3, 2026
@github-actions

github-actions Bot commented Apr 3, 2026

Copy link
Copy Markdown
Contributor

Pyrefly Diff

base → PR
--- /tmp/pyrefly_base.txt	2026-04-03 01:32:36.759263086 +0000
+++ /tmp/pyrefly_pr.txt	2026-04-03 01:32:28.061383933 +0000
@@ -740,7 +740,7 @@
 ERROR Object of class `NoneType` has no attribute `version` [missing-attribute]
   --> tests/test_containers_integration_tests/services/plugin/test_plugin_service.py:68:16
 ERROR Argument `Literal['custom']` is not assignable to parameter `preferred_provider_type` with type `ProviderType | SQLCoreOperations[ProviderType]` in function `models.provider.TenantPreferredModelProvider.__init__` [bad-argument-type]
-   --> tests/test_containers_integration_tests/services/plugin/test_plugin_service.py:377:37
+   --> tests/test_containers_integration_tests/services/plugin/test_plugin_service.py:401:37
 ERROR Object of class `NoneType` has no attribute `open_id` [missing-attribute]
    --> tests/test_containers_integration_tests/services/test_account_service.py:530:16
 ERROR Object of class `Tenant` has no attribute `role` [missing-attribute]

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

Labels

size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: plugin upgrade fails when .difypkg file missing from disk (PVC recreation)

1 participant