When importing and processing files into Assets Server, there may come a time that the system is left with many empty folders that need to be removed.
Example: Dozens of images are imported daily from multiple agencies and stored in multiple folders. As per the licensing terms with these agencies, these images have to be deleted after a certain time period. This can be done automatically, but this process leaves behind empty folders.
This article describes how to identify and delete empty folders in Assets Server.
Before you start
It cannot be emphasized enough that when this process is created that there MUST BE A DRY RUN flag included in the implementation.
Warning: Data is about to be deleted; do not run this process unless you are absolutely sure of the results. You are responsible for the end results of this processing.
It is advised to read through the full article and fully understand it before performing the actions.
How it works
The process involves running a series of API calls in which folders are identified as empty and subsequently deleted.
It follows a post-order traversal pattern: children are always evaluated and deleted before their parent.
This ensures that a folder containing only empty subfolders is correctly identified as empty once those subfolders have been removed.
Actions
The following table shows the actions to perform and their API calls to execute. For more information about the API calls, see the API reference section below.
| # | Action | Description and API call |
|---|---|---|
| 1 | Get root folder |
Resolve the top-level folder by path to obtain its unique ID. This ID is used for all subsequent traversal calls.
|
| 2 | List child folders |
Using the folder ID, retrieve all immediate subfolders. Results are paginated at 100 items per page. Continue paging (incrementing from) until a page returns fewer results than the page size. Note: The paging value is determined by the caller and NOT by Assets Server (see the REST API in the Management Console).
|
| 3 | Recurse down the tree |
For each subfolder returned, repeat Step 2. Continue recursing until a folder list call returns an empty array — this signals that there are no further subfolders at that branch. |
| 4 | Check if folder is empty |
For the deepest folders first, search for any assets whose ancestor path matches the folder path. A total hit count of 0 confirms that the folder (and all its descendants) is empty.
|
| 5 | Delete empty folder |
If the total hit count is 0, issue a DELETE request using the folder ID. The designated folder will be deleted.
|
| 6 | Work back up the branch |
After processing all children, re-evaluate each parent folder. A parent that previously contained only empty subfolders will now also return 0 assets and can be deleted. |
| 7 | Protect non-empty folders |
At no point should a folder containing assets (directly or in any descendant) be deleted. The search in Step 4 covers the entire subtree, so this check is always comprehensive. |
API reference
The following sections explain each API call in more detail.
GET /api/folder/get
This resolves a folder by its path and returns its ID, name, and permission string.
|
Example response:
|
The permissions string must include 'D' (delete) for the API token in use. The example above does include this.
GET /api/folder/list
This returns an array of immediate child folders for a given folder ID.
Pagination is controlled via from (offset) and size (page size).
Stopping condition: An empty array [] — not a null path — signals no further subfolders exist.
GET /services/search
This searches for assets using an Assets Server query syntax. Field filters use a colon notation (not equals signs).
-
Correct syntax:
q=ancestorPaths:"/WW Connect/SubFolder" -
Incorrect syntax:
q=ancestorPaths="/WW Connect/SubFolder"
Example: /services/search?q=ancestorPaths:"/WW Connect/Empty/Empty3"
DELETE /api/folder/{id}
This permanently deletes a folder by its ID.
- Returns HTTP 200 on success.
- Returns HTTP 204 if there is no content to delete.
- Returns HTTP 403 when there are not sufficient permissions for deleting.
- Returns HTTP 404 if the folder no longer exists (safe to treat as non-fatal in automated runs).
Caveats & known risks
The following table shows caveats and known risks to be aware of.
| Risk | Detail and mitigation |
|---|---|
| Pagination gap |
If a folder has more than 100 subfolders, a single list call will miss them. Always loop with an incrementing from offset until a page returns fewer results than the page size. Be sure to adjust the value in the call. |
| Traversal order |
Post-order (children before parents) is mandatory. If a parent is evaluated before its empty children are deleted, it will appear non-empty and will not be cleaned up in that run. |
| Root folder protection |
The root folder passed as input (such as /WW Connect) should never be deleted regardless of whether it ends up empty. The implementation must explicitly skip deletion of the root. |
| Permissions |
The API token must have Delete ('D') permission on each folder targeted for deletion. Check the permissions field in the /api/folder/get response. Insufficient permissions will result in HTTP 403 errors. |
| Race condition |
If assets are being uploaded or moved into a folder while the process is running, the folder could be incorrectly identified as empty. Schedule this process during off-hours or low-activity windows. |
| Deletion is permanent |
There is no recycle bin or undo for folder deletions via the API. Always run in dry run mode first and review the output before performing live deletions. |
| HTTP 404 on delete |
A 404 response on a DELETE call means the folder was already removed (for example by a prior run or another user). This is non-fatal and can be safely ignored in automated runs. |
| Large folder trees |
Very deep or wide trees (500+ folders) may hit memory or timeout limits depending on the execution environment. For Workato JS actions, monitor the job duration. For standalone Node.js scripts, this is generally not a concern. |
| Search query syntax |
Field filters in the Assets search API use colon notation ( An incorrectly formed query will return unexpected results and may cause non-empty folders to be flagged as empty. |
Dry run mode
All implementations of this process (see the next section) should include a dry run flag. When enabled, the process traverses the full folder tree and identifies all folders that would be deleted, but issues no DELETE API calls.
The recommended workflow is as follows:
Step 1. Set dry_run = true).
Step 2. Run the process and review the log output or deleted_folders result.
Step 3. Confirm that every listed folder is safe to remove.
Step 4. Only then set dry_run = false and run the process again for live deletion.
Implementation
This process can be implemented in the following forms, all using the same core logic:
- Standalone Node.js script. Run directly from the command line. Requires Node 18+ (uses native fetch). Configure via environment variables or the CONFIG block at the top of the file.
- Workato recipe. Multi-step recipe using a callable sub-recipe for paginated folder listing and a BFS queue stored as job variables. Suitable for scheduled or triggered runs.
- Workato JavaScript action. Single self-contained script for use inside a Workato Run JavaScript step. Inputs and outputs are mapped as datapills. Outputs include a summary string, deleted folder list, and error details.
Comments
0 comments
Please sign in to leave a comment.