cellSaveData: Focus the list head when NEWDATA has no new data #19895

Open
digant73 opened 8:25pm on October 20, 2026 wants to merge 45 Ξ” into rpcs3/rpcs3 master from
cellsavedata-newdata-focus

Pull Request Overview

  • Opened on October 20, 2026
  • Status Open
  • Commit count 1 with first commit October 20, 2026

Total Delta

45 Total Diff Delta

Open Days

Open 18 weekdays

Test Delta

0 Diff Delta in Test Files
Breakdown by Phase

How long has this pull request spent in each phase of its lifecycle?

Data pending calculation for pull request

Author avatar

cellSaveData: Focus the list head when NEWDATA has no new data

Analysis, hwtest and fixes made by Opus 5.5. Tested by me.

(confirmed) Fixes #19163
Relates https://github.com/RPCS3/rpcs3/pull/18873

Bug (#19163)
When the save slot limit is reached, some games hide the "New Save" entry (listSet->newData = NULL) but keep focusPosition = CELL_SAVEDATA_FOCUSPOS_NEWDATA. RPCS3 rejected this with CELL_SAVEDATA_ERROR_PARAM (param error 34) and never showed the list, so saving silently failed (God of War III at 32 saves, Cars Race O Rama at 5). The check came from #7742 (d58f52ff3), and real hardware confirms it only for Delete lists. This replaces the earlier attempt in #18873, which had no hardware evidence.

Fix (cellSaveData.cpp, +27/-2)
- Load/Save lists with focus NEWDATA and no new data entry now focus the list head (empty list β†’ no focus) instead of failing. Delete lists keep error 34.
- Delete lists reject a listSet->newData entry with CELL_SAVEDATA_ERROR_PARAM, and their initial focusPosition is DIRNAME (console: 0 for Delete, 1 for Load/Save).
- The load confirmation for the new data entry shows its title.

Hardware test (PSL1GHT, 22 cases, saves NDT5-A…E / NDT1-A / none)

SAVEDATA_NEWDATA_FOCUS_HWTEST.zip

  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”

β”‚ Case β”‚ Call β”‚ Focus β”‚ newData β”‚ PS3 β”‚ This β”‚ Upstream β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ PR β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ β”‚ HEAD / β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ C1–C4 β”‚ ListLoad2 β”‚ TAIL / β”‚ NULL β”‚ A / E / D / C β”‚ same β”‚ same β”‚
β”‚ β”‚ Γ—5 β”‚ LATEST / β”‚ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ β”‚ OLDEST β”‚ β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C5, C6 β”‚ ListLoad2 β”‚ NEWDATA β”‚ NULL β”‚ head (NDT5-A, β”‚ same β”‚ err 34 β”‚
β”‚ β”‚ Γ—5, Γ—1 β”‚ β”‚ β”‚ NDT1-A) β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C7 β”‚ ListLoad2 β”‚ NEWDATA β”‚ NULL β”‚ "no data" β†’ β”‚ same β”‚ err 34 β”‚
β”‚ β”‚ Γ—0 β”‚ β”‚ β”‚ CELL_CANCEL β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C8, C9 β”‚ ListSave2 β”‚ NEWDATA β”‚ NULL β”‚ head (NDT5-A, β”‚ same β”‚ err 34 β”‚
β”‚ β”‚ Γ—5, Γ—1 β”‚ β”‚ β”‚ NDT1-A) β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C10 β”‚ ListSave2 β”‚ NEWDATA β”‚ NULL β”‚ "no data" β†’ β”‚ same β”‚ err 34 β”‚
β”‚ β”‚ Γ—0 β”‚ β”‚ β”‚ CELL_CANCEL β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C11 β”‚ ListLoad2 β”‚ 0xFF β”‚ NULL β”‚ err 34 β”‚ same β”‚ same β”‚
β”‚ β”‚ Γ—5 β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C12–C14 β”‚ ListDelete β”‚ NEWDATA β”‚ NULL β”‚ err 34 β”‚ same β”‚ same β”‚
β”‚ β”‚ Γ—1, Γ—0, Γ—5 β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ β”‚ NEWDATA / β”‚ HEAD / β”‚ β”‚ β”‚ crash in β”‚
β”‚ C15–C17 β”‚ ListDelete β”‚ NEWDATA / β”‚ TAIL / β”‚ PARAM error β”‚ same β”‚ C15, β”‚
β”‚ β”‚ Γ—5 β”‚ TAIL β”‚ HEAD β”‚ β”‚ β”‚ C16–C22 not β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ run β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C18 β”‚ ListLoad2 β”‚ NEWDATA β”‚ HEAD β”‚ new entry β”‚ same β”‚ β€” β”‚
β”‚ β”‚ Γ—5 β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ β”‚ ListSave2 β”‚ NEWDATA / β”‚ HEAD / β”‚ β”‚ β”‚ β”‚
β”‚ C19–C21 β”‚ Γ—5 β”‚ NEWDATA / β”‚ TAIL / β”‚ new entry β”‚ same β”‚ β€” β”‚
β”‚ β”‚ β”‚ HEAD β”‚ HEAD β”‚ β”‚ β”‚ β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ C22 β”‚ ListSave2 β”‚ TAIL β”‚ TAIL β”‚ NDT5-E β”‚ same β”‚ β€” β”‚
β”‚ β”‚ Γ—5 β”‚ β”‚ β”‚ β”‚ β”‚ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

This PR matches the PS3 in all 22 cases. Upstream differs in C5–C10 and crashes in C15: it hits an out-of-range index on save_entries (-1) in delete_save when the new entry is picked in a Delete list.

Quick summary

In God of War III cellSaveDataListSave2 silently fails if the max save "slot" count is reached, preventing the user from saving.

Details

I have seen multiple users come to the rpcs3 discord help channel due to being unable to save in God of War III, when interacting with the save point the screen dims like its opening the save list but it closes with no feedback whatsoever before returning to gameplay.

I initially assumed this to be a game bug, but after looking at the function responsible for calling cellSaveDataListSave2 in the game executable I was unable to find anything obviously wrong so I tested this on my console and saving functions as intended even after creating 32 manual saves(the maximum that the game allows).

On real hardware with 32 saves present the save list opens as expected, but the option to select "Create New Save" is not present forcing the user to overwrite a previous save if they wish to save their progress.

On rpcs3 the specific error message written to the log when it fails is as follows: E {PPU[0x100002c] Thread (SaveDataUtil::SaveHDD) [HLE:0x006903cc, LR:0x0023f028]} cellSaveData: savedata_op(): listSet->newData is null while listSet->focusPosition is NEWDATA E {PPU[0x100002c] Thread (SaveDataUtil::SaveHDD) [HLE:0x006903cc, LR:0x0023f028]} SYS: 'cellSaveDataListSave2' failed with 0x8002b404 : CELL_SAVEDATA_ERROR_PARAM, 34 [1]

I vaguely remember this working long ago when I did my Oblivion playthru and the game properly hid the "Create New Save" option once I reached the max saves that game allowed(128 if I remember correctly) however I was unable to locate a build where I could get God of War III saving to work when 32 saves are present.

Attach a log file

Log: RPCS3.log

Attach capture files for visual issues

No response

System configuration

RPCS3 v0.0.42-19699-3d587726 Alpha | master Windows 11 25H2 AMD Ryzen 5 8400F 6-Core Processor | 12 Threads | 15.59 GiB RAM 6000Mhz NVIDIA GeForce GTX 1070 running on driver 582.28.0.0

Other details

Possibly affects other titles that use cellSaveDataListSave2 for saving, but is less likely to be noticed due to them setting a higher max save "slot" count.

No comments have been left on this PR.