RBAC: GET /datasets/batch_import_status/<job_id> always returns 400 when RBAC_ENABLED
- Dominant language
- TypeScript
- Stars
- 156k
- Forks
- 24.6k
- Avg merge
- 22h 9m
- Merged PRs (30d)
- 610
Description
### Self Checks
- [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542).
- [x] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general).
- [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones.
- [x] I confirm that I am using English to submit this report, otherwise it will be closed.
- [x] 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
- [x] Please do not modify this template :) and fill in all the required fields.
### Dify version
1.16.1 (`main`)
### Cloud or Self Hosted
Self Hosted (Docker), Self Hosted (Source)
### Steps to reproduce
Requires `RBAC_ENABLED=true`. With the default (`false`) the gate short-circuits and everything works.
1. Start a segment batch import:
`POST /console/api/datasets//documents//segments/batch_import`
→ `200 {"job_id": "...", "job_status": "waiting"}`
2. Poll that job for its status, as the UI does:
`GET /console/api/datasets/batch_import_status/`
3. → `400`
```json
{"code": "invalid_param", "message": "Missing dataset_id or pipeline_id in request path", "status": 400}
```
### ✔️ Expected Behavior
The status endpoint returns the batch import job status, gated on the caller's permission for the dataset the job belongs to.
### ❌ Actual Behavior
`400 invalid_param`. The view never runs, so segment batch import progress cannot be polled at all — the UI's polling call (`web/service/knowledge/use-segment.ts:213`) fails for every account, including workspace owners.
**Root cause**
`DatasetDocumentSegmentBatchImportApi` binds one `Resource` class to two routes (`api/controllers/console/datasets/datasets_segments.py:602-606`):
```python
@console_ns.route(
"/datasets//documents//segments/batch_import",
"/datasets/batch_import_status/",
)
class DatasetDocumentSegmentBatchImportApi(Resource):
```
Both methods carry dataset-scoped RBAC gates that keep the default `resource_required=True`:
- `post` → `RBACPermission.DATASET_EDIT` (`:617`)
- `get` → `RBACPermission.DATASET_READONLY` (`:671`)
Flask-RESTX binds every route on the class to every method, so both methods are reachable at `/datasets/batch_import_status/` — a path that carries no `dataset_id`. `enforce_rbac_access` then calls `_extract_resource_id` (`api/controllers/common/wraps.py:167-178`), which finds neither `dataset_id` nor `pipeline_id` and raises `ValueError`. That is mapped to `400` by `handle_value_error` (`api/libs/external_api.py:92-97`), before the view body executes.
**Suggested fix**
This is the same root cause as #39930, but the remedy is different. There, the permission key is workspace-level, so passing `resource_required=False` is correct. Here both keys are genuinely per-dataset, so suppressing the resource id would turn this into an unscoped permission check over a Redis key (`segment_batch_import_{job_id}`) that carries no tenant or dataset — a weaker guarantee than intended.
The route shape is what needs to change: give the status endpoint its own dataset-scoped path and its own `Resource` class, e.g.
```
/datasets//batch_import_status/
```
That also needs the frontend polling URL updated in `web/service/knowledge/use-segment.ts:213`.
Contributor guide
Research direction
Start with DatasetDocumentSegmentBatchImportApi in api/controllers/console/datasets/datasets_segments.py and inspect enforce_rbac_access and _extract_resource_id in api/controllers/common/wraps.py. Check the polling call at web/service/knowledge/use-segment.ts:213 and verify the batch-import POST and status GET with RBAC_ENABLED=true. Done means the status route carries the dataset context, preserves dataset-scoped permission checks, and the UI polling request succeeds.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- flask, python, typescript
- Domain
- api, authorization, backend, frontend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100