apache / apache/shenyu

[BUG] ScalePolicyCache stores partial DTO-derived DO → null-field NPE in scaling path

Open
#6,624 1 comment 0 reactions 0 assignees View on GitHub
admin priority: high type: bug
Dominant language
Java
Stars
8.8k
Forks
3.1k
Avg merge
7d 1h
Merged PRs (30d)
85

Description

- severity: High
- files: `shenyu-admin/src/main/java/org/apache/shenyu/admin/service/impl/ScalePolicyServiceImpl.java:80-88`; `shenyu-admin/src/main/java/org/apache/shenyu/admin/model/entity/ScalePolicyDO.java:230-252`; `shenyu-admin/src/main/java/org/apache/shenyu/admin/scale/scaler/cache/ScalePolicyCache.java`; `shenyu-admin/src/main/java/org/apache/shenyu/admin/scale/scaler/ScaleService.java`
- description: `ScalePolicyServiceImpl.update` builds `scalePolicy = ScalePolicyDO.buildScalePolicyDO(scalePolicyDTO)` from the (partial) web DTO. `ScalePolicyDTO.num`/`beginTime`/`endTime` are nullable (no `@NotNull`). `buildScalePolicyDO` sets `.num(item.getNum())` etc., so null DTO fields → null DO fields. `updateByPrimaryKeySelective` correctly writes only non-null columns (DB retains old values) BUT `scalePolicyCache.updatePolicy(scalePolicy)` puts the *partial* DO (with null `num`/`beginTime`/`endTime`) into the cache. `executeScaling()` then reads from the cache (not DB). For policy `"1"` it calls `kubernetesScaler.scaleByNum(activePolicy.getNum())` — `getNum()` returns boxed `Integer` auto-unboxed to primitive `int`, NPE if null. For policy `"2"` it calls `now.after(policy.getBeginTime())` where `getBeginTime()` is null → NPE.
- impact: Enabling/updating a scale policy with a partial DTO corrupts the in-memory cache (cache/DB divergence) and throws NPE inside `executeScaling`; the corrupted cache entry persists and breaks all subsequent scaling cycles.
- suggested_fix: After `updateByPrimaryKeySelective`, re-read the full row (`scalePolicyMapper.selectByPrimaryKey(id)`) and cache that merged DO; or have `buildScalePolicyDO` merge against the existing cached/DB row. Gate `executeScaling` on null fields.
- confidence: High
- related_existing: none. Not a dup of PERF-11 (unbounded caches); this is selective-update/DB-vs-cache divergence specific to ScalePolicy.

---
_Identified during the 2026-08-02 deep re-scan; full list in [`docs/scan2-2026-08-02/00-consolidated-critical-high.md`](docs/scan2-2026-08-02/00-consolidated-critical-high.md)._

Contributor guide

No contributing guide indexed for this repository

Research direction

Start with ScalePolicyServiceImpl.java:80-88 and trace the update flow through ScalePolicyCache.java and ScaleService.java, then inspect ScalePolicyDO.java:230-252. Verify how a partial DTO reaches the cache and how executeScaling reads it. Done means the cache contains the merged policy values after a selective update and subsequent scaling cycles no longer hit null-field NPEs.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, kubernetes
Domain
backend, devops
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Quiet
Clarity
Clearly specified
Newbie friendliness
67/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.