Bug: Service API QA segment updates clear the answer when it is omitted
- 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.17.0
### Cloud or Self Hosted
Self Hosted (Source)
### Steps to reproduce
1. Run Dify Self Hosted from source at commit `1299d99b2d70b1b639819248715dd3340979665f`.
2. Create or select a knowledge base with a document in QA mode (`doc_form=qa_model`). Create a completed and enabled segment with content `old question` and answer `old answer`.
3. Using a dataset API key, update only the content through the Service API:
```http
POST /v1/datasets/{dataset_id}/documents/{document_id}/segments/{segment_id}
Authorization: Bearer
Content-Type: application/json
{"segment": {"content": "new question"}}
```
4. Retrieve the segment and inspect `answer`, `status`, `enabled`, and `error`.
5. Repeat with the high-quality indexing technique. A keywords-only partial update also reproduces the answer loss:
```json
{"segment": {"keywords": ["new keyword"]}}
```
This was verified through the real Service API `SegmentService.update_segment` path with a real SQLAlchemy SQLite session.
### ✔️ Expected Behavior
The API should not mutate an existing QA segment when a required `answer` is missing.
Please confirm which contract is intended:
1. If QA updates require an answer, reject the request with a clear HTTP 400 validation error before mutation or indexing, and leave the existing segment unchanged. The schema and API documentation should state that `answer` is required for QA updates.
2. If partial updates are supported, an omitted `answer` should preserve the existing answer. An explicitly supplied answer should replace it, with the behavior for `null` or an empty string documented.
### ❌ Actual Behavior
The request is accepted, but an omitted answer is converted to `None` and written into the segment.
- Economy indexing: the existing answer is persisted as `null` while the segment remains `completed` and enabled. This causes silent data loss.
- High-quality indexing: the update attempts to concatenate the content with `None`, causing `can only concatenate str (not "NoneType") to str`. The exception is caught internally; the segment is persisted as `error` and disabled, while the Service API still returns HTTP 200.
- A keywords-only update has the same answer-clearing behavior.
The relevant code currently allows an optional answer in `SegmentUpdateArgs`:
https://github.com/langgenius/dify/blob/main/api/services/entities/knowledge_entities/knowledge_entities.py#L253
The QA update path then assigns `segment.answer = args.answer`:
https://github.com/langgenius/dify/blob/main/api/services/dataset_service.py#L3713
Local focused verification passed: Service API controller tests (111), SegmentService tests (42), and update_segment focused tests (13). Existing tests did not cover a QA partial update with an omitted answer.
Related context: Issue #6251 documents `answer` as required when creating a QA document; this report concerns the inconsistent behavior of the Service API segment update endpoint.
If maintainers confirm this issue is valid, please assign this issue to me so I can prepare the PR. I will wait for confirmation before opening the PR.
Contributor guide
Research direction
Start with SegmentUpdateArgs in api/services/entities/knowledge_entities/knowledge_entities.py and the QA update path in api/services/dataset_service.py. Run the listed Service API controller, SegmentService, and update_segment tests, then add focused coverage for omitted answers on QA and keywords-only updates. Done means the agreed validation or preservation contract is enforced without mutating the existing segment.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python, sqlalchemy, sqlite
- Domain
- api, backend, database
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 58/100