Plugin installation failed, stuck in infinite loop. How to stop?

Hello everyone, I deployed dify1.11.4 in local docker. When installing the Tongyi plugin, it fell into an infinite loop. The error message displayed “Task timed out but not properly terminated”. However, the installation did not stop, but kept repeating until I had nearly a hundred plugin installation failure records.

I saw someone mention in other topics that this issue can be resolved by sending a POST request. However, I am deploying locally and do not have an authorization value. I cannot fix it using this step.

After plugin installation fails, the interface always shows ‘1 plugin installing’

I’d like to ask if anyone has a good way to stop the installation?

There are other values, ask AI
There are other values, ask AI

docker logs docker-plugin_daemon-1

@Dify_Forum_Helper, please follow up.

You can first follow the steps below to troubleshoot and “brake,” trying to avoid using the POST interface you mentioned that requires Authorization.


1. First, confirm if the plugin daemon process is still frantically retrying

Execute on the deployment server (you’ve been prompted once before):

docker logs docker-plugin_daemon-1 -n 200

Check if recent logs are constantly repeating similar entries:

  • A certain plugin install task
  • Constantly reporting Task timed out but not properly terminated

If so:

  • It’s very likely that a certain “installing” task is stuck, and the plugin daemon is constantly retrying.

To “brake” first, you can temporarily stop this container:

docker stop docker-plugin_daemon-1

This can first prevent the continuous refreshing of failed installation records.
(Then restart: docker start docker-plugin_daemon-1)


2. Without using the POST interface, how to get local Authorization?

Even with local deployment, the frontend will still carry a Bearer Token when accessing Dify; the browser just passes it for you.

You can get this token this way, and then use it to call the POST interface you saw in another post (the “clean up plugin installation status” interface):

  1. Open your Dify webpage in a browser (e.g., http://localhost:3000 or your own domain) and log in normally.
  2. Open browser developer tools:
    • Chrome/Edge: F12 → Select the “Network” tab.
  3. Click on any page that accesses the backend (e.g., enter “Studio”, “Apps”, etc.).
  4. In the Network panel, find an interface with a request path similar to /console/api/... and click on it.
  5. In “Headers”, find the Authorization field, which is usually:
    Authorization: Bearer xxxxxxx...
    
  6. Copy out the long string of token after Bearer. (Be careful not to leak it to others)

This way you will have the Authorization value for your local deployment, and you can call that repair interface just like with the cloud version.


3. Using the obtained Token to call the “clean up installing tasks” interface

You should have already seen the specific interface path and method in the post you referenced, which is usually a POST request.

You can use curl (on the server) to send it:

curl -X POST "http://<your_backend_address>/xxx/xxx" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <the token you just copied>" \
  -d '{
    // Fill in the body according to that post
  }'

Note a few things:

  • <your_backend_address>: If you are using default docker-compose, it’s usually:
    • Access from host browser: http://<server_IP>:3000
    • But the actual API backend port might be 5001/8000, etc., which needs to match your own configuration (check the API service mapping in docker-compose.yml).
  • The interface path and body parameters must strictly follow the post you referenced (to avoid accidentally deleting other records).

After a successful call, refresh the Dify page. Usually:

  • The “Installing Plugin” prompt in the top right corner will disappear;
  • The Tongyi plugin will become “Not Installed” or a failed state, and you can try reinstalling it later (it’s recommended to troubleshoot image/network issues first).

4. If you really cannot/do not want to use the API, you can consider a more “hardcore” approach (use with caution)

This method carries higher risks and is only suitable if you have some database operation experience and are willing to perform database backups:

  1. Stop Dify related containers (to avoid write conflicts)
    docker compose down
    
  2. Back up data in the database container (Postgres):
    • Find the Postgres container name, e.g., docker ps shows dify-postgres-1;
    • Use pg_dump to export:
      docker exec -t dify-postgres-1 pg_dump -U <db_user> <db_name> > dify_backup.sql
      
  3. Enter the database, find the table related to “plugin installation tasks”, and change the status from installing / pending to failed or directly delete that record.

However, because table structures and field names may vary across different versions, if you reach this step, it’s best to post your version number from docker-compose.yml, database information, and a section of the relevant table structure for further discussion, to avoid incorrect operations.


5. I suggest you can now reply to the post with two things

  1. Execute on the server:

    docker logs docker-plugin_daemon-1 -n 200
    

    Paste the key error (including a few lines above and below Task timed out but not properly terminated) into the post.

  2. Following step 2 above, get Authorization: Bearer ... in your browser, confirm you can capture the token, and if you have questions, you can post a screenshot of the redacted request headers.

With this information (logs + your version (1.11.4)), if it still gets stuck later, it will be possible to more accurately determine if it’s a known issue with the current version, or a problem with the Tongyi plugin’s own installation (e.g., network, Python source, image).


:books: Potentially helpful documentation (related to the issue)

:label: Version Information

  • You are currently on v1.11.4. The plugin system is relatively mature, but issues related to plugin installation/dependency installation are continuously being fixed in subsequent versions. If the official Release notes later mention fixes for issues like “plugin installation timeout/stuck in installation”, it is recommended to consider upgrading if conditions permit.

Plugin installation always fails, whether it’s local installation or marketplace installation, it shows “Task timed out but not properly terminated”. Below are my Docker logs. My Dify version is 1.11.4. Please help me check it, thanks.

@Dify_Forum_Helper Please continue to follow up

这两位的情况其实已经把线索给得很全了,我帮你们汇总一下“怎么刹车 + 怎么清理 + 怎么避免再次卡死”,都针对 1.11.4。


I. What phenomenon are you currently encountering?

Based on Niklaus1028’s logs, it’s roughly:

  • Continuously polling APIs like /plugin/<plugin-id>/management/install/tasks, /dispatch/model/schema, etc.;
  • With occurrences of:
    • task xxx timed out
    • record not found (SELECT * FROM "plugin_declarations" WHERE plugin_unique_identifier = 'alipay/alipay_plugin:0.1.0@...')

Combined with ao_zhang’s description:

  • The UI constantly displays “Installing Plugin”;
  • Background task Task timed out but not properly terminated;
  • The same plugin (Tongyi / Alipay, etc.) has installation tasks repeatedly created.

This indicates:

  1. A certain installation task has timed out, but its status was not correctly marked as “finished,” causing the daemon process to continuously believe it’s still installing;
  2. Some plugins’ plugin_unique_identifier cannot be found in the DB (record not found), but the installation process continues to be scheduled, further messing up the state.

II. First, “Brake” – Stop the Daemon Process from Continuously Spawning Tasks

On your server, first stop the plugin daemon process container:

docker stop docker-plugin_daemon-1

Purpose:

  • Immediately stop creating new installation tasks and stop continuously logging Task timed out...;
  • Facilitate subsequent cleanup (otherwise, new tasks will be spawned again right after cleaning).

Start it again after cleaning:

docker start docker-plugin_daemon-1

III. How to Obtain Authorization (Bearer Token) in a Local Deployment Environment

You are all using 1.11.4 docker-compose self-hosting. Even locally, the frontend will automatically carry a Bearer Token when accessing the backend, it’s just usually not visible.

Steps (using Chrome/Edge as an example):

  1. In your browser, access your Dify admin panel (e.g., http://SERVER_IP or http://localhost), and log in normally with an administrator account.
  2. Press F12 to open developer tools → Switch to the “Network” panel.
  3. Click on any other menu item on the page (e.g., enter “Apps”, “Datasets”, etc.) to ensure an API request is sent.
  4. In the Network list, find a request with a path similar to /console/api/... and click on it.
  5. In “Headers”, find:
    Authorization: Bearer xxxxxxxx...
    
  6. Copy the long string of token after Bearer (keep it for yourself, do not post it on the forum).

With this token, you can use curl on the server to call the cleanup API without needing “cloud-specific” Authorization.


IV. Cleaning Up “Stuck Installation Tasks”

In the previous post titled “After plugin installation fails, the UI always shows 1 plugin installing,” there is already a dedicated POST API endpoint and body template for “cleaning up installation task status.” You can follow the instructions there.

The general way to call it is as follows (replace the path and body with the actual content provided in that post):

curl -X POST "http://<YOUR_BACKEND_ADDRESS>/<API_PATH_FROM_THAT_POST>" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <TOKEN_COPIED_IN_PREVIOUS_STEP>" \
  -d '{
    ... Fill in the JSON body from that post here ...
  }'

Note:

  • <YOUR_BACKEND_ADDRESS>:
    • If you started it directly using the official Docker directory, Nginx usually exposes both the frontend and backend on port 80. You can directly use http://<SERVER_IP> or the address you currently use to access Dify;
    • If you have a custom reverse proxy, please use the domain/port through which your frontend normally accesses Dify.
  • For the path and request body, please follow exactly what was provided in that old post. Do not guess, to avoid accidentally deleting other plugins or task statuses.

After a successful call:

  • Refresh the Dify page.
    • The “Installing Plugin” prompt in the top right corner should disappear;
    • The stuck plugin should change to “Not Installed” or a failed state.

V. If All Plugins Still Time Out After Cleanup, Which Direction Should You Troubleshoot?

You are all on 1.11.4, and:

  • Local installation (uploading difypkg) also times out;
  • Marketplace installation also times out;
  • Continuous timeout and record not found in logs.

This usually indicates that it’s not an issue with a single plugin, but rather that the plugin runtime environment itself is abnormal. Several key areas:

1. Machine Performance and Docker Resources

Plugin installation involves creating a Python virtual environment and downloading dependencies within the plugin container. If the machine is “tight”:

  • Insufficient CPU/memory;
  • Too few resources allocated by Docker;

Both can cause tasks to run very slowly or even time out. Corresponding actions:

  • Confirm the machine has at least:
    • 2 CPU cores, 4GB+ RAM (official minimum recommendation suggests 8GB for more stability);
  • In Docker Desktop (if on Mac/Win), appropriately increase CPU / Memory;
  • On the server, use top/htop to observe if CPU / MEM are maxed out during installation.

2. Is External Network / Python Source Access Smooth in the Plugin Container?

Based on other plugin posts, many installation failures in 1.11.x versions are due to:

  • The default PyPI source being unreachable or very slow;
  • Network policies or proxies blocking the plugin container from accessing the external network.

Troubleshooting:

  1. Enter the plugin daemon container:
    docker exec -it docker-plugin_daemon-1 /bin/bash
    
  2. Inside the container, try:
    ping pypi.org
    curl -I https://pypi.org/simple
    
    If it’s completely unreachable or has extremely high latency, installation will easily time out.

Consider:

  • Setting a domestic Python source for plugins in .env (if supported by the official version you are using);
  • Or configuring a network proxy at the host level to ensure the container can access the external network normally.

3. What Does record not found Indicate?

In your logs, similar to:

SELECT * FROM "plugin_declarations" WHERE plugin_unique_identifier = 'alipay/alipay_plugin:0.1.0@...' ... record not found

This indicates:

  • The plugin declaration was not successfully written to the database;
  • But subsequent steps of the installation process are still querying based on this plugin_unique_identifier and cannot find a record.

After you use the API to clean up installation tasks:

  • It is recommended to reopen the plugin marketplace/plugin management page;
  • To avoid accumulating old “dirty” states, first install only a simple plugin for testing (e.g., the built-in official demo plugin):
    • If even the simple plugin times out, it’s an “environment-level issue”;
    • If the simple plugin works, but certain specific plugins fail, then focus on the dependencies and network of those specific plugins.

VI. If API Cleanup Still Doesn’t Work, Only Two “Reset State” Paths Remain (High Risk)

Consider this only if you confirm data can be backed up and you have experience with database operations:

  1. Full Stack Shutdown + Database Backup

    docker compose down
    

    Assuming the Postgres container is named docker-db_postgres-1, backup:

    docker exec -t docker-db_postgres-1 \
      pg_dump -U <db_user> <db_name> > dify_backup.sql
    
  2. Enter the database and delete or change the status of plugin-related “installation tasks” and “installing states” to failed.
    Table names/fields vary slightly across different versions for this step. It is not recommended to guess field names yourself, as it’s very easy to accidentally delete other things.
    If you must take this path, it is recommended that you open a separate post or add here:

    • Dify version and Postgres-related configuration in docker-compose.yml;
    • A screenshot of the plugin-related table names and structure using \dt;
      Then we can together deliberate on the specific SQL.

VII. Next Steps for Your Feedback to Facilitate Precise Localization

It is recommended that both of you add the following information to this post:

  1. Execute:

    docker logs docker-plugin_daemon-1 -n 200
    

    Redact and paste the log segments containing Task timed out but not properly terminated and record not found.

  2. Following the steps above to obtain Authorization: Bearer ..., attempt a POST call for “cleaning up installation tasks”:

    • Which API path was used for the call?
    • What was the returned HTTP status code (200 / 4xx / 5xx)?
    • After the call, refresh the UI. Did the “Installing Plugin” prompt disappear?
  3. After cleanup, try installing the simplest plugin again to see if it still consistently reports Task timed out but not properly terminated.

As long as we can confirm:

  • The cleanup API can successfully “reset” stuck tasks;
  • But new installations still time out;

Then we can basically conclude that it’s an “environment/network/resource” issue, rather than just a one-time dirty data problem. Afterwards, we can provide targeted guidance for environment optimization, or suggest considering an upgrade to a newer version (subsequent versions have indeed had continuous fixes for plugin installation timeouts and task cleanup).


:books: Related Documentation

If it’s convenient for you, please first go through the three steps above: “brake + get token + call cleanup API,” then reply to this post with the execution results. We can then together narrow down the root cause to either an “environment issue or a version bug.”

docker logs -f docker-plugin_daemon-1 to check this docker logs, and reinstall it again.

What should I do if I still can’t find this value? :melting_face:

Authorization is indeed a bit “hidden.” Let me help you confirm the points you might have missed by following the most detailed steps.

Below, you don’t need to look at any code or server logs; you can just operate in the browser.


First, confirm two things

  1. You must be “successfully logged in” before searching

    • You need to be on Dify’s normal homepage (with menus like “Apps / Workflows / Datasets” on the left).
    • Not on the /install initialization page.
  2. You must look at API requests, not HTML / images or other static files


“Nanny-level process” for finding Authorization in Chrome / Edge

If you are using Firefox / Safari, there are additional notes at the end.

  1. Open the Dify page and log in

    • E.g.: http://localhost or http://your_server_IP.
    • Enter your account and password to enter the normal workbench page.
  2. Open Developer Tools

    • Press F12 on the keyboard
    • Or right-click on a blank area of the page → “Inspect”
  3. Switch to the “Network” tab

    • Top tabs usually include: Elements / Console / Sources / Network / …
    • Make sure to click into Network.
  4. Refresh the page once (very crucial)

    • With the Network panel open, press the browser’s refresh button or Ctrl+R / Cmd+R.
    • After refreshing, many request entries will start appearing in the Network list.
  5. Filter only API requests
    There is usually a row of filter buttons above the Network panel:

    • All / Doc / JS / XHR / Fetch / Img / …
    • Please click “XHR” or “Fetch” (if “All” is available, you can choose “All”, but XHR / Fetch is cleaner).
  6. Find a request with /console/api/ in its path

    • For example:
      • /console/api/account/profile
      • /console/api/apps
      • Or other /console/api/... forms
    • If you can’t see it at a glance, you can type /console/api into the search box in the upper right corner of the Network panel to filter.
  7. Select this /console/api/... request and switch to Headers

    • Click on a request row → a details panel will appear on the right;
    • It will have several tabs like: Headers / Payload / Preview / Response;
    • Please select Headers (sometimes it may be displayed as “标头 / 请求头”).
  8. Find Authorization in Headers

    • Scroll down to the “Request Headers” area;
    • Find a line similar to this:
      Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
      
    • If found:
      • Double-click or right-click to copy the value in this entire line;
      • What you really need is the long string of token after Bearer.

If you still can’t see Authorization, these are the common situations

Situation 1: You are not actually logged in successfully

  • Characteristics:
    • You are visiting the /install registration page, or you were redirected back to the login page after logging in;
    • In Network, /console/api/account/profile returns 401 (UNAUTHORIZED);
    • In this case, the browser usually does not carry the Bearer token after login.
  • Suggestion:
    • First, confirm that you have completed the initialization and first administrator registration;
    • After logging in, you can see the complete menu on the left side of the page;
    • Then follow the steps above to find the /console/api/... request.

Situation 2: Wrong request type selected

  • If you clicked:
    • document type (HTML), img (image), js (script),
    • These requests often do not have Authorization.
  • Solution:
    • Click XHR / Fetch at the top of Network to only view API requests;
    • Then select the ones whose paths contain /console/api.

Situation 3: You are using Firefox / Safari, the interface is slightly different

The general idea is the same, just the menu names are slightly different:

  • Firefox:

    1. F12 → Select “Network”;
    2. Refresh the page;
    3. Select the /console/api/... request;
    4. In the right panel, find “Headers” → Authorization in “Request headers”.
  • Safari (you need to enable “Develop menu” in preferences first):

    1. Menu bar “Develop” → “Show Web Inspector”;
    2. Select “Network”;
    3. The method is the same as above.

Situation 4: You are looking at Network at the reverse proxy frontend layer (e.g., Cloudflare debugging)

  • Authorization will only appear in the request from browser → your Dify frontend domain;
  • If you are looking at traffic in another intermediate layer (e.g., a management console), it might have been hidden or desensitized.

If convenient, you can reply like this, and we can help you confirm

  1. After following the steps above, in Network:

    • Take a screenshot of the /console/api/... request selected, with the Headers tab open;
    • Censor the Authorization line with a mosaic before sending it;
    • This way, we can confirm if you clicked on the “correct request”.
  2. Tell us which browser and system you are using:

    • For example: Chrome 122 / Edge 121, Windows 11 / macOS, etc.

As long as you can find any /console/api/... request in Network, Authorization must be in its request headers; if we can see the interface you are currently seeing, we can likely pinpoint it for you in a few steps.

What should I do if I can’t find this value? :melting_face:


I asked GPT and it solved it, saying that my frontend using cookies wouldn’t send authorization.
Execute in the web developer tools console:
`(async () => {
// 1) Try to get csrf_token from cookie (some versions use this name)
const csrfFromCookie =
document.cookie.split(‘; ‘).find(x => x.startsWith(‘csrf_token=’))?.split(’=’)[1];

// 2) Fallback to localStorage / sessionStorage (different versions might put it here)
const csrfFromStorage =
localStorage.getItem(‘csrf_token’) ||
sessionStorage.getItem(‘csrf_token’) ||
localStorage.getItem(‘X-CSRF-Token’) ||
sessionStorage.getItem(‘X-CSRF-Token’);

const csrf = csrfFromCookie || csrfFromStorage;

if (!csrf) {
console.error(‘CSRF token not found. Please click on any /console/api request in Network and copy the X-Csrf-Token value from Request Headers.’);
return;
}

const res = await fetch(‘/console/api/workspaces/current/plugin/tasks/delete_all’, {
method: ‘POST’,
headers: {
‘Content-Type’: ‘application/json’,
‘X-CSRF-Token’: decodeURIComponent(csrf), // :star:Key point
},
credentials: ‘include’,
body: JSON.stringify({}),
});

const text = await res.text();
console.log(‘status:’, res.status);
console.log(‘body:’, text);
})();`

After stopping, and then re-executing docker start docker-plugin_daemon-1, it started downloading again once opened. Is there a way to stop it?

Here’s how to solve it:

  1. Find the relevant token on the plugins page.

  2. Call the API.

1 Like