Dify plugin install
Use this when installing, upgrading, listing, or repairing Marketplace plugins. Login first (Dify console API). Failures: Dify troubleshooting.
Resolve IDs
Marketplace https://marketplace.dify.ai, header X-Dify-Version: <running Dify version, e.g. 1.17.0>.
- Batch:
POST /api/v1/plugins/batch{"plugin_ids":["langgenius/openai"]}→latest_package_identifier/ plugins[]. unique id - Search:
POST /api/v1/plugins/search/advanced(plain/searchoften empty) - Download URL:
GET /api/v1/plugins/download-url?unique_identifier= - Unique id:
org/name:version@sha256
If host batch works but the api container times out, skip marketplace install and use the offline path.
Online install
POST /console/api/workspaces/current/plugin/install/marketplace
{"plugin_unique_identifiers":["org/name:version@checksum"]}
Poll GET .../plugin/tasks. Healthy list: GET .../plugin/list. Daemon must log local runtime ready.
Install 3–8 at a time. One bad id can fail a batch.
plugin-daemon image tag is independent of api/web. After a Dify upgrade, if every model provider goes red, bump daemon to the version in that release (1.17 needed a newer *-local daemon than 1.16). Do not assume api:1.17.0 implies the old daemon still works.
Offline / no-egress (nested cloud VMs)
Do not open iptables FORWARD or a host CONNECT proxy.
- Host: download
.difypkgfrom the download-url API. POST /console/api/workspaces/current/plugin/upload/pkg(multipart file) → unique identifier.POST .../plugin/install/pkg{"plugin_unique_identifiers":["..."]}.- uv inside plugin_daemon installs Python deps. If it cannot reach pypi.org, use the local PEP 503 index already pointed at by
PIP_MIRROR_URL/UV_INDEX_URL:- Host
pip download <req> -d .../pypi-mirror/packages(cp312 manylinux x86_64 and abi3). - Rebuild
simple/<pkg>/index.htmlwith href/packages/<filename>. - Delete
plugin_daemon/cwd/.uv-cache/simple-v24.UV_NO_CACHE=1is not enough (--cache-dir).
- Host
- Retry install. Logs:
failed to install dependenciesvslocal runtime ready/Installed tool:.
Fat extras (markitdown[all], GPU stacks) need every extra wheel or they fail after the .difypkg itself uploaded.
Failed-task UI
GET .../plugin/tasks keeps old failures even after a later success. POST .../plugin/tasks/delete_all clears the red list. Trust plugin/list + daemon logs.
Flags
FORCE_VERIFYING_SIGNATURE=false— unsigned/community packages.MARKETPLACE_ENABLED=trueunless fully air-gapped.- Raise
PLUGIN_MAX_PACKAGE_SIZEandNGINX_CLIENT_MAX_BODY_SIZEtogether or upload 413s.
Intranet vs SaaS
Prefer user-supplied URL: OpenAI-compatible, vLLM, Xinference, SQL, Redis, SSH, SMTP, HTTP Request node (builtin). Skip extra Google/Tavily/Exa unless asked. Official ids sometimes do not exist (langgenius/vllm → community vLLM plugin; langgenius/time → a datetime tool).
langgenius/mineru tool parse-file with server_type=local does not poll. If the local MinerU /file_parse is async (task_id only), wrap it in a reusable workflow: try the plugin, then fall back to the site's OpenAPI submit_parse / task_status / task_result loop. List first (GET .../plugin/list); do not install extra OCR plugins unless asked.
Proven: local plugin patches (upgrade-safe note) + PaddleOCR
- A plugin's source lives in
plugin_daemon/cwd/<org>/<name>-<ver>@<hash>/. Small fixes can be applied in place (e.g. prefix relative/files/...URIs withINTERNAL_FILES_URL), thencompose up -d --no-deps --force-recreate plugin_daemonand wait forlocal runtime ready. Every plugin upgrade/reinstall wipes the patch — re-apply after upgrades (documented in the workflow repo). - Path splits: first install
0.0.26-eraplugins still expose per-tenant credentials viaprovidersrows; checkGET /workspaces/current/model-providers/{provider}/credentialsfor the key name beforeadd. - PaddleOCR (
langgenius/paddleocr 0.3.0):text_recognition(PP-OCRv6) /document_parsing(PP-StructureV3) /document_parsing_vl(PaddleOCR-VL-1.6); hosted async jobs polled inside the plugin. Do not sendoutputFormatsto VL (API 422OCR服务请求失败) — leave it unset.fileparam passes Dify file objects; relative URIs must be patched or setFILES_URL/INTERNAL_FILES_URLproperly. - Scan-document fallback pattern in DSL:
document-extractor(default-value) → if-else text-layer length< N→ OCR tool → clean (strip LaTeX$\underline{...}$and<img>tags) → merge with text layer → review pipeline. Verify with a real no-text-layer PDF.
Uninstall & same-id version switch (1.17)
- Upload:
POST /workspaces/current/plugin/upload/pkg— multipart field ispkg(notfile); response{unique_identifier}. - Uninstall:
POST /workspaces/current/plugin/uninstall{"plugin_installation_id": <id from GET plugin/list>, "preserve_credentials": false}. - Upgrading the same plugin-id: daemon compiles the new package, but the workspace keeps the OLD installation active until you uninstall + install the new identifier. Symptom: "I bumped the version but behavior is unchanged". Verify active version via
plugin/list → meta.plugin_unique_identifier. - Launch failures surface in
GET .../plugin/tasks(status failed) and daemon logs; a failed launch leaves no runtime —docker logs plugin_daemonshows the pydantic/yaml error (see plugin-development addendum). - Restart window: calls during daemon restart fail
no available node, plugin runtime not found— retry afterlocal runtime ready; the api side may also log transientConnectError: Name or service not knownforplugin_daemon.
Plugin regression rollback (1.17, minimax 0.0.27 incident)
When a marketplace upgrade breaks model invocations:
- Check
plugin/list → meta.plugin_unique_identifierfor the current version. - Old version directory still in daemon cwd (
docker/volumes/plugin_daemon/cwd/<org>/<plugin>-<ver>@<hash>/) if not garbage-collected — pack it:cd <dir> && find . -type f -not -path './.venv/*' -not -name '*.pyc' | zip -q /tmp/rollback.difypkg -@. - Upload (
POST .../upload/pkgfieldpkg) → uninstall current ({"plugin_installation_id":..., "preserve_credentials":true}— model credentials live in api DB, this preserves them) → install old. - Archive the rollback difypkg in your delivery repo (
vendor-plugins/) for next time. - Pin the version in ops docs; test any future upgrade on a staging workspace first.