langgenius / langgenius/dify

Chat API returns HTTP 400 invalid_param when sensitive_word_avoidance sent with `enabled: false` + extras

Open
#38,409 1 comment 1 reaction 0 assignees View on GitHub
🐞 bug project#dify
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

main branch (uncommitted)

### Cloud or Self Hosted

Self Hosted (Source)

### Steps to reproduce

Discovered by peaks-loop code-sweep on 2026-07-02 (related to issue #38327).

1. Spin up Dify self-hosted from `main`.
2. Send a chat completion request with this exact payload body:

```json
{
"inputs": {},
"query": "hello",
"response_mode": "blocking",
"user": "abc",
"sensitive_word_avoidance": {"enabled": false, "type": "", "config": {}}
}
```

3. Observe the response: HTTP 400 with body `{"error": "invalid_param", "message": "Extra inputs are not permitted: type, config"}`.

The trace points at `pydantic.ValidationError` raised inside `core/app/app_config/common/sensitive_word_avoidance/manager.py`.

### ✔️ Expected Behavior

Disabled (`enabled=False`) sensitive-word avoidance configs should silently drop `type` / `config` extra keys so the request flows through without an HTTP 400. The disabled branch should only persist `{enabled: False}` regardless of extra fields the client sent.

### ❌ Actual Behavior

When a chat request carries `{"sensitive_word_avoidance": {"enabled": false, "type": "", "config": {}}}`, the existing `_normalize_raw()` in `core/app/app_config/common/sensitive_word_avoidance/manager.py` falls through every branch: `enabled` is not None, `enabled` is not True, so the leftover `type` / `config` fields are passed straight through to the discriminator-tagged union.

`SensitiveWordAvoidanceDisabledConfig` is declared with `extra="forbid"`, so pydantic raises `ValidationError("Extra inputs are not permitted: type, config")` and the API returns HTTP 400 `invalid_param` — matching the trace in issue #38327.

**Proposed change:** Extend `_normalize_raw()` in `api/core/app/app_config/common/sensitive_word_avoidance/manager.py` to drop every key other than `enabled` when `enabled is False`. Add two parametrized cases to `api/tests/unit_tests/core/app/app_config/common/test_sensitive_word_avoidance_manager.py`:

- `test_validate_disables_when_enabled_false_or_missing` covering the regression (empty leftover fields and non-empty leftover fields).

**Risk:** The disabled case already returns `None` from `convert()` and only persists `{enabled: False}` from `validate_and_set_defaults({...}, mode_dump())`, so the cleanup only affects the input-normalization boundary, not the persisted shape. The `enabled is True` branch and the `enabled is None` branch are untouched. `ModerationFactory.validate_config` is still called for each enabled config, unchanged. No schema, migration, controller, or frontend changes.

Related: issue #38327 (no linked PR).

Contributor guide

Open the contributing guide

Research direction

Start in api/core/app/app_config/common/sensitive_word_avoidance/manager.py by reading _normalize_raw(), then run api/tests/unit_tests/core/app/app_config/common/test_sensitive_word_avoidance_manager.py. Add coverage for disabled configurations with empty and non-empty extra fields; done means both cases avoid HTTP 400 while enabled and missing-enabled behavior remains unchanged.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.