Declared imports
Handing the broker a save, state or memory card it did not write, and what each refusal means.
What an import is
A save archive the broker wrote is restored path for path. A save from
somewhere else (another emulator, real hardware, an EmulatorJS export)
has no path the broker knows. So RomM declares it instead: the member goes
under .import/<kind>/ in the archive, and the manifest says what it is.
{
"version": 2,
"created_at": 1789000000,
"files": [
{ "path": ".import/save/Game.srm", "kind": "save", "origin": "standalone" }
]
}kind is save, state or memcard, and it must match the path's second
segment. origin is emulatorjs, standalone, hardware or unknown.
It is advisory: it sharpens a refusal but never changes where a member lands.
Every import member is checked before the working slot is cleared. If any member is refused, nothing is written and activate answers 422:
{
"detail": {
"error": "import_refused",
"refusals": [
{
"reason": "kind_not_accepted",
"member": ".import/save/Game.srm",
"expected": "no imports",
"detail": null,
"suggest_emulator": null,
"docs": "/docs/api/imports#kind-not-accepted"
}
],
"truncated": 0
}
}At most 200 refusals are listed; truncated counts the rest. A crash while
checking imports answers 500 with
{"detail": {"error": "import_preflight_failed"}}, still before anything is
cleared.
Fourteen emulators accept imports so far. RetroArch, Flycast, DuckStation,
PPSSPP, Dolphin, PCSX2, RPCS3, ScummVM, Cemu, Azahar, Eden, shadPS4, xemu and
Xenia take the kinds listed under
What each emulator takes, and every other
emulator refuses each import member with kind_not_accepted. The structural
checks run first either way: a bad manifest answers manifest_invalid and a
bad path answers unsafe_path. When the session syncs the memory card on its
own routes, a member that would land on that card answers
memcard_synced_separately. If the card is the emulator's whole save tree,
the archive is not restored at all and every import member answers
memcard_synced_separately. Emulators opt in one at a time.
The refusals are sorted by member, then by reason; an archive-level refusal
has member: null and sorts first. In an archive that holds imports, a
regular member that would have failed the restore is listed here too, as
unsafe_path, unrecognised_layout or unreadable_member, with the old
error text as its detail. An archive without imports keeps its old
save restore failed: <message> answer.
Activate's response lists each placed import under save_restore.imported,
as {member, dest, sidecars}. The exit dump then ships every placed file
even if the game never touched it, and lists those paths under the
manifest's imported key, so an import is never lost to the "only what
changed" rule.
What RomM can tell the broker
Three optional rom fields on activate help an emulator place an import:
| Field | Purpose |
|---|---|
title_id | RomM's game id for the rom: a serial, title id or game code. |
save_target | RomM's name for where this game keeps its saves, such as a PS2 card folder. |
save_target_layout | How save_target names that place: folder-exact, folder-prefix, file-exact, file-prefix or folder-split. |
A save_target_layout the broker does not know is logged and passed
through; it never fails the launch.
Asking what an emulator takes
GET /streaming/api/session/import-spec?emulator=pcsx2&platform=ps2This answers import_api, manifest_version, the emulator and platform
it was asked about, the accepted kinds (each with its shapes,
requires_resume_slot and max_members), state_channel, card_subtree,
state_slot, the value to send as save.resume_slot (null when the
emulator takes no states, neither mid-session nor in the archive) and the
full list of reasons. It needs X-Broker-Secret like every other
RomM-facing route and answers 403 without it. An unrecognised emulator
answers 422 unknown emulator: <name>.
A 404 from this route means the broker predates imports. Never send
.import/ members to that broker: it cannot place them, and they would
never reach the emulator.
Each emulator answers with the kinds it takes on the platform it was asked
about; What each emulator takes lists them. A
kind with an empty shapes list is refused on that platform, and the
refusal says why. An emulator that takes nothing answers kinds: [] and
state_channel: "none".
For an emulator author, the answer comes from Emulator.import_spec(). It
takes no arguments and reads the platform from self.platform; the default
accepts nothing. The registry tests hold every spec to the same rules. A
declared state kind means state_channel: "archive", at most one state
counting the archive's own, and requires_resume_slot. A push channel
needs mid-session save states. The tests also place one example member of
each kind, on one platform per emulator, and check that it lands inside the
save tree. For every import, that rule is enforced when the plan is checked
at activate: each file an import writes, sidecars such as an owner marker
included, must land in a save subtree and not resolve out of the save root
through a symlink, or the member is refused.
What each emulator takes
emulator | save | memcard | state |
|---|---|---|---|
retroarch | one .srm, on a platform whose core loads one, or one .sav where the core reads it as its .srm; on wii, title folders, title/<type>/<title id>/data/; on 3ds, folders inside Azahar's sdmc/Nintendo 3DS/ or nand/data/ | not taken; expected names save | PUT /api/session/state-file after activate |
flycast | raw 131072-byte vmu_save_<A-D><1-2>.bin images, and dc_nvmem.bin | a raw 131072-byte VMU (Dreamcast memory card) image | one .state; needs save.resume_slot |
duckstation | a raw 131072-byte .mcd, .mcr, .mc or .srm card | the same as save | one <serial>_resume.sav or <serial>_<n>.sav; needs save.resume_slot |
ppsspp | PSP save folders, SAVEDATA/<product code><suffix>/, each holding PARAM.SFO | not taken | one <game id>_<version>_<n>.ppst, with its .jpg screenshot if sent; needs save.resume_slot |
dolphin on ngc | GameCube .gci saves, each in <region>/Card A/ | the same as save | one <game id>.sNN that opens with the game's id; needs save.resume_slot |
dolphin on wii | Wii title saves, title/<type>/<title id>/data/ | not taken | one <game id>.sNN that opens with the game's id; needs save.resume_slot |
pcsx2 | one folder memory card: <card>/_pcsx2_superblock and its game folders | the same as save | PUT /api/session/state-file after activate |
rpcs3 | PS3 save folders, home/00000001/savedata/<SAVEDIR>/ and game/<DIR>/, each holding PARAM.SFO | not taken | one .SAVESTAT, .SAVESTAT.zst or .SAVESTAT.gz; needs save.resume_slot |
scummvm | <game>.NNN and <game>.sNN save files | not taken | one <game>.sNN or <game>.NNN file; needs save.resume_slot |
cemu | Wii U save data for the game being launched: usr/save/00050000/<title>/ | not taken | not taken |
eden | Switch NAND save folders, nand/user/save/<space>/<user>/<title>/, with the profile store an account save needs | not taken | not taken |
azahar | 3DS save data from an unencrypted SD card or NAND folder: title/ and extdata/ folders | not taken | not taken |
xemu | the launched game's UDATA/<title id>/ and TDATA/<title id>/ folders | not taken | not taken |
xenia | Xbox 360 save folders, content/<XUID>/<title id>/00000001/, with their Headers/ file | not taken | not taken |
shadps4 | PS4 save folders, <serial>/<save dir>/ | not taken | not taken |
Dolphin takes nothing on any other platform, and Desktop takes nothing yet.
RetroArch renames the .srm after the game being launched and places it
in saves/<library_name>/, where the core loads it. library_name is the
name the core reports about itself, such as mGBA or Genesis Plus GX, not
the manifest's core (see
RetroArch cores).
On a platform that takes a .srm, it takes one per archive: a second one, or a
save the archive already carries at the same path, is a destination_conflict.
On the 15 of those platforms whose core reads a .sav as its .srm, a .sav
is placed as the .srm, and discovery lists <name>.sav there
(RetroArch cores
lists them). A .sav and a .srm in the same archive would both become that
one file, so both get destination_conflict.
wii and 3ds take folders instead, described below the list. It refuses these:
- On
psp:destination_unresolvable, withsuggest_emulator: "ppsspp". The PPSSPP core keeps SAVEDATA folders, not a.srm. - On
ngc:shape_unverified. The Dolphin core keeps GameCube saves as GCI files in its own folders, which imports don't place yet. Import throughdolphininstead; this refusal names nosuggest_emulator. - A
.srmonwiior3ds:unrecognised_layout, whatever its name. The detail names the kind of folder that platform takes. - On any other platform whose core loads no
.srm, such asdcorarcade:destination_unresolvable. The core keeps its save in a file of its own, or has none. Discovery lists nosaveshapes there, and RetroArch cores lists the 25 platforms that take a.srmand where each other core keeps its save. - On a platform RetroArch has no core for:
destination_unresolvable. - On a platform that takes a
.srm, a.rtc,.nv,.eepor.mpkfile, and a.savwhere the core does not read one as its.srm:needs_conversion, until each core's name for that file has been checked. A platform that takes no.srmgives its own refusal above first. Onwiiand3dsa file with one of those names is judged as part of a save folder, so it gets the folder refusals instead. - A
memcardmember:kind_not_accepted, withexpectednamingsave. On a platform that takes a.srm, send the core's.srmas a save instead. - A
statemember:state_uses_push. Onjaguar, whose core has no states, and on a platform RetroArch has no core for, it iskind_not_accepted.
On wii, the Dolphin core keeps the same emulated NAND as standalone Dolphin,
and a save is a game's title folder, under save:
- Its path is
title/<type>/<title id>/data/..., where the type is00010000,00010001or00010004. It can sit underWii/, undersaves/dolphin-emu/User/Wii/or directly under.import/save/. It lands insaves/dolphin-emu/User/Wii/title/, with the title id lower-cased. - The title id must be RomM's
title_id, or it isidentity_mismatch. RetroArch reads no id off the rom, so with notitle_idthe title is taken on trust. - A loose
data.binisneeds_conversionand anand.binissource_incompatible, as under Dolphin.title/00000001/and a title'scontent/folder areprotected_destination.sys/andticket/areunrecognised_layouthere, since the core's save folders leave them out, and so is anything else, a.gciincluded.
On 3ds, the Azahar core's SD card and NAND are placed exactly as named, and
nothing is renamed:
- A member must already sit under
saves/Azahar/Azahar/, and then insidesdmc/Nintendo 3DS/<id0>/<id1>/title/<high>/<low>/...,sdmc/Nintendo 3DS/<id0>/<id1>/extdata/<high>/<low>/...ornand/data/<id0>/.... Every id0 and id1 is 32 hexadecimal digits. (The Azahar core nests its ownAzahar/folder under thesaves/Azahar/dir RetroArch already sorted it into.) - A title's id, its high and low halves together, must be RomM's
title_id, or it isidentity_mismatch. Extdata and NAND data carry no title id and are not held to one, and with notitle_ida title is taken on trust. nand/data/<id0>/sysdata/and a title'scontent/folder areprotected_destination.- Anything else, including a member that does not already sit under
saves/Azahar/Azahar/, isshape_unverified. Azahar's layout has not been checked against a running core beyond these paths, so the broker refuses rather than guess.
Flycast places every file loose in its data folder, flycast/, under the
name Flycast reads:
- A VMU save keeps its name, with the port letter upper-cased.
dc_nvmem.bin, the console's system flash, must not be empty. - A
memcardmember goes in the VMU socket its name picks, such asvmu_save_C2.bin, or else in A1. - A RetroArch
.srmissource_incompatible, because it isn't a VMU image. A.vms,.vmi,.dcior.dcmexport isneeds_conversion. - The state is renamed after the game being launched,
<rom>.state, and gets the owner marker that lets the broker resume it.
DuckStation keeps memory card 1 as one shared card (see DuckStation):
- A card of either kind becomes
memcards/shared_card_1.mcd, so an archive takes one card. A headered card (.gme,.psm,.ps,.ddf,.mem,.vgsor.psx) isneeds_conversion. - A card in an archive that already carries another card under
memcards/is adestination_conflict. Once the shared card exists, the other card is never mounted again. - The state is renamed
<serial>_resume.savand gets the owner marker that lets the broker resume it. The serial is RomM'stitle_idwhen it sends one, else the serial in the member's name, else the name's own base. A member named for a different serial than RomM's isidentity_mismatch.
PPSSPP places PSP save folders in its SAVEDATA folder, where PSP games
look for them, and one state in its working slot:
- A save folder is named for the game's product code (four capital letters
and five digits) and a suffix the game picks, such as
ULUS10041DATA00. It can sit underPSP/SAVEDATA/, underSAVEDATA/or directly under.import/save/, and a copy of a whole memory stick, with one folder of its own abovePSP/, works too. A folder whose name holds no product code isunrecognised_layout. - Every save folder needs its
PARAM.SFO, the file PPSSPP lists a save by. A folder without one isincomplete_unit, detailmissing PARAM.SFO. - A save folder's product code is only logged when it differs from RomM's
title_id: a sequel can read the saves of the game before it. - A lone file, with no save folder around it, is
unrecognised_layout, since a PSP save is a folder, and a lone RetroArch.srmissource_incompatible. Anything underPSP/SYSTEM/isprotected_destination. Any other folder underPSP/, such asPSP/GAME/, isunrecognised_layout, and so is aPPSSPP_STATE/folder sent as a save, with a detail saying to declare it as a state. - The state keeps the game id and version in its name,
<game id>_<version>_<n>.ppst; only the slot number is rewritten. A.jpgscreenshot of the same name rides along, is renamed with it and does not count as a second state. Either can sit underPSP/PPSSPP_STATE/, underPPSSPP_STATE/or directly under.import/state/. - The state's game id must be RomM's
title_id, when RomM sends one, or it isidentity_mismatch. An id that is not a product code, as a homebrew game's often is, is taken on trust. - A screenshot sent without its state is
incomplete_unit, and so is an empty state. A RetroArch state issource_incompatible. Amemcardmember iskind_not_accepted: a PSP has no memory card.
Dolphin takes what the console being launched keeps. On ngc, a
GameCube save is a .gci file, under save or memcard alike:
- Its path must end in
<region>/Card A/<name>.gci, where the region isUSA,EURorJAP. It can sit underGC/, undersaves/dolphin-emu/User/GC/or directly under.import/<kind>/. It lands in the same folder underGC/, the Slot A card. Dolphin shows a game only the folder for its own region, so a save sent to another region's folder is placed but never seen. - A GCI's game code is only logged when it differs from the game being launched: a game can read another game's saves.
- A
.gcianywhere else, loose or underCard B/say, isunrecognised_layout. So is one whose size is not a 64-byte header followed by whole 8 KiB blocks, and one named.GCIin capitals. A.gcsor.savexport isunrecognised_layouttoo. A whole card image,.raw,.mcdor.gcp, isneeds_conversion: export each save from it as a.gci. - An archive that already carries a card under
GC/refuses an imported GCI asdestination_conflict: one GameCube card per archive.
On wii, a save is a game's title folder from the NAND, under save:
- Its path is
title/<type>/<title id>/data/..., where the type is00010000,00010001or00010004. It can sit underWii/, undersaves/dolphin-emu/User/Wii/or directly under.import/save/. It lands inWii/title/, with the title id lower-cased as Dolphin writes it. - The title id must be the game being launched, or it is
identity_mismatch. When the broker has no id for the game being launched, the title is taken on trust. - A loose
data.bin, outside a title'sdata/folder, isneeds_conversion: it is the export a Wii writes to an SD card, so import it with Dolphin's Import Wii Save and send the title folder that makes. Anand.binissource_incompatible: send the title folder from the dump instead.sys/,ticket/,title/00000001/and a title'scontent/folder areprotected_destination. Anything else, a.gciincluded, isunrecognised_layout. Amemcardmember iskind_not_accepted.
On either console, the state is one .sNN file, directly under
.import/state/ or under StateSaves/:
- It must open with a game id, or it is
unrecognised_layout, and that id must be the game being launched, or it isidentity_mismatch. The game being launched is the id Dolphin's rom holds, read off an.iso,.gcmor.wbfsimage, else RomM'stitle_id. With neither, the id is taken on trust. With the rom's id in hand, the state is held to all six characters, maker code included, since the broker would otherwise refuse to resume it at boot. - It is renamed after the id it opens with, in the broker's slot: Dolphin finds a state by the running disc's id, not by the file's name.
lastState.sav, Dolphin's undo buffer, isprotected_destination. An empty state isincomplete_unit, and a RetroArch state issource_incompatible.
PCSX2 takes one folder memory card and makes it the Slot 1 card,
memcards/<card>/, where <card> is
PCSX2_SLOT1_CARD (romm-slot1 by
default):
- The card is one folder holding
_pcsx2_superblockand the card's game folders, undersaveormemcardalike. It can sit undermemcards/or directly under.import/<kind>/. The folder's own name is replaced by the Slot 1 card's. - One card per archive. Two card folders are a
destination_conflictwhose detail names both, and so is a card in an archive that already carries a card undermemcards/. - A card without
_pcsx2_superblockisshape_unverified: PCSX2 does not mount a folder without one, and the files may be one game's folder from a card rather than a whole card. A card whose_pcsx2_superblockis empty isincomplete_unit. - A single file is no folder card. A card image or a single-save export
(
.ps2,.mc2,.mcd,.mcr,.bin,.max,.psu,.cbs,.xpsor.sps) isneeds_conversion, and any other file isunrecognised_layout. Either way, send the folder card instead. - A card holds every game's saves, so no member is held to the game being launched.
- A
statemember isstate_uses_push. Send it with the state-file PUT after activate, which refuses a state named for another game's serial.
RPCS3 places PS3 save folders in its dev_hdd0 and one state in its
savestates folder:
- A save folder holds
PARAM.SFOat its root. Save data goes tohome/00000001/savedata/<SAVEDIR>/and can arrive underdev_hdd0/home/<user>/savedata/,home/<user>/savedata/,PS3/SAVEDATA/orSAVEDATA/. The user is eight digits and is rewritten to00000001, the only user the broker's layout has, so two users' folders of one name are adestination_conflict. Game data goes togame/<DIR>/and can arrive underdev_hdd0/game/orgame/. - A folder with none of those around it is
unrecognised_layout: RPCS3 keeps save data and game data apart, and a bare folder does not say which it is. So is a folder name of anything but letters, digits,_and-, up to 32 of them, a single file where a folder belongs, and a state sent as a save. - A folder without
PARAM.SFOat its root isincomplete_unit, detailmissing PARAM.SFO. One further down does not count. - A folder named for another game's serial is placed and only logged: a sequel or DLC writes its predecessor's folders.
home/<user>/exdata/andhome/<user>/trophy/, a game'sUSRDIR/EBOOT.*, RPCS3's lock folders undergame/(a name starting with$or its full-width form) and the game folder of the installed title being booted areprotected_destination. An installed title is anEBOOT.BINunder the game folder, or a.pkg.- The state is one
.SAVESTAT,.SAVESTAT.zstor.SAVESTAT.gz, in exactly that case, alone or in one folder named for the game's serial. It is renamed<serial>_import.SAVESTATand filed under the serial the launch will look in. The serial is the one the boot target holds; RomM'stitle_idis not used. A boot target with none, a bare.iso, refuses a state asidentity_unknown, and a folder named for another serial isidentity_mismatch. An empty state isincomplete_unit, and a RetroArch state issource_incompatible.
ScummVM names every save after a target, the name scummvm --add
registers a game folder under in scummvm.ini, and keeps saves and states in
one folder:
- A save is one file,
<game>.NNNor<game>.sNN, directly under.import/save/or undersaves/. Its<game>must be a name of the game in the rom folder, in any case: a target, the game id or the engine id. It lands assaves/<name>.<ext>with the name asscummvm.inispells it. A save for another target of the same folder, such as another language, keeps that target's name, and only shows in a session that boots that target. - A name that is none of the folder's is
identity_mismatch, listing the ones that are. A folder ScummVM detects no game in isidentity_unknown. A genericSAVEGAMEname, a.srm, a.stateandscummvm.iniareunrecognised_layout. - A save in the working slot under the session target's own name is a
destination_conflict, whose detail says to declare it as a state. The same slot under another name is an ordinary save. - The state is one
<game>.sNNor<game>.NNNfile naming any target of the folder. It is renamed onto the session's target in the working slot, keeping its spelling. It counts every save the archive already carries in that slot under the session target's name, so leave the old one out. - The first import into a folder ScummVM has not seen registers it, which runs
scummvm --addand can take up to two minutes. The registration stays even if the import is then refused.
Cemu, Eden, Azahar, xemu, Xenia and shadPS4 take saves and nothing else.
A state or memcard member is kind_not_accepted, since none of them has
either. A save that lands on a file the archive already holds is a
destination_conflict. The import does not merge with the archive's copy, so
leave that copy out to send the new one.
Cemu keeps one account, 80000001, and files every save under it:
- A save is
usr/save/00050000/<title>/, withuser/<account>/,user/common/andmeta/inside. The tree can sit undermlc01/usr/save/,storage_mlc/usr/save/,usr/save/orsave/. A save collected as one 16-digit Saviine folder name is split. A donor console's account folder,user/<8 hex digits>starting with8, becomesuser/80000001. Two different donor accounts in one archive are adestination_conflictfor every file that names one, whileuser/common/andmeta/files are not held to it. - The title folder is lower case, as Cemu writes it, and must be the game
being launched: RomM's
title_idis read as the title's low half, such as1010EC00, or as the whole sixteen-digit id, such as000500001010EC00. Another game's save isidentity_mismatch. A path that names its own title is still placed when RomM sends notitle_id. - A member that names no title, such as
user/80000001/slot0.dat, is placed under the launched game's when RomM names one, and isidentity_unknownwhen it does not. A sixteen-digit id of any other title type, such as an update's0005000E..., names no save folder, so it is read as no id. - Anything under
usr/save/whose first folder is not a title id, the account storesystemincluded, isprotected_destination. A title type other than00050000isunrecognised_layout. So is auser/<x>folder that is neithercommonnor an account id of that shape, an account folder with no file in it, a loose file, and a00050000/...path with none of the wrappers above.
Eden takes verbatim NAND exports:
- A save is
nand/user/save/<space>/<user>/<title>/<files>. The ids are upper-cased, as Eden writes them. When RomM sends atitle_id, the title must be the game being launched, or it isidentity_mismatch. - A device save, whose user is 32 zeros, stands alone. An account save needs
the profile store in the same import,
nand/system/save/8000000000000010/, or it isincomplete_unit. The check is that the import holds at least one file under that folder; it does not verify that the store is complete. - An archive that already carries a profile store refuses the imported one as
destination_conflict, and its own store does not stand in for the import's. So an account save can only be imported into an archive with no profile store yet. - A
bis/folder, aNintendo/orsdmc/folder and a.binfile that fits no shape and is too large to be a save (a raw dump) aresource_incompatible. A path that starts with a title id, a JKSV folder and a Checkpoint folder name no save space or profile Eden could find, so they aredestination_unresolvable. Anything else, a loose file and the rest of the NAND included, isunrecognised_layout.
Azahar takes the folders of a 3DS SD card or NAND that has not been encrypted, and rewrites the console and card ids to the ones it uses:
- Saves are
title/<high>/<low>/...andextdata/<high>/<low>/...undersdmc/Nintendo 3DS/<id0>/<id1>/, andextdata/<high>/<low>/...undernand/data/<id0>/. The ids are 32 hex digits. The SD card's folders can sit undersaves/Azahar/Azahar/orNintendo 3DS/, or be the two ids alone. The NAND's can sit undersaves/Azahar/Azahar/or be bare. (The doubled form is where the RetroArch build of this same core actually writes, and is what an archive dumped through RetroArch now carries. A singlesaves/Azahar/with no secondAzahar/is never what the core itself produces, so it is left unrecognised rather than guessed at.) The<high>and<low>folders are lower-cased. - A
title/save is held to the game being launched whenever RomM names it, and another game's isidentity_mismatch. The game is named bysave_target, the title's<high>/<low>pair, or, when there is none, bytitle_id, which is that same pair written as one sixteen-digit id. With neither the title is taken on trust. Anextdatafolder is not checked, since its id is not always the game's. - An SD card whose ids are not zeros and which has a
dbs/orbackups/folder beside itstitle/is a console's, and encrypted: every member under that card's ids, the folder's own files included, issource_incompatible. A donor card with no such folder is taken, and its ids rewritten. Two cards' copies of one title are adestination_conflict, since they land in one folder. - A JKSM or Checkpoint backup folder is
shape_unverified. A file undersysdataisprotected_destination. Atitle/orextdata/tree with no console and card folders above it isunrecognised_layout. - A loose file, or a bare
data/folder, at the top of the archive names no title. It isdestination_unresolvablewhen RomM sends atitle_idor asave_target, andunrecognised_layoutotherwise. The broker never places a member fromsave_targetalone.
xemu files a save under its own title id, which must be the session's, and the launch then writes it into the hard drive image:
- A save is
UDATA/<title id>/<files>orTDATA/<title id>/<files>, at the top of the member's path. The folder names can be in either case, and land upper-cased. The session's title id comes from the disc's own certificate, and from nowhere else: another game's folder isidentity_mismatch, and a disc whose certificate cannot be read isidentity_unknowneven when RomM sends atitle_id. - The disc's title id is also what the launch clears stale saves under and what the exit dumps, and it does neither without one. A save taken on RomM's word alone would reach the shared hard drive image, outlive every later session and never leave in a dump, so it is refused instead.
- A folder above
UDATAorTDATA, such as a drive letter, a partition folder orsaves/, isunrecognised_layout. A whole hard drive image, named.qcow2,.img,.raw,.vhd,.vhdxor.vmdkor opening with the qcow2 header, issource_incompatible. A file under a title folder is a save whatever its name. - FATX stores names of 42 bytes at most, so a longer one is
unsafe_path. Names compare without regard to case:Save.datandsave.datare one file, so they are adestination_conflict, and so is a save that differs from the archive's copy only in case.
Xenia files a save under the profile that is signed in, which the
broker reads from logged_profile_slot_0_xuid in Xenia's config,
xenia-edge.config.toml under its storage root:
- The key is found in any table. Its value is 16 hex digits, with or without
0x, in either case, and the folder is named for it in upper case. A missing file, a missing or blank key, a value that is not a XUID, or two different XUIDs isdestination_unresolvable: create a profile on the desktop first. - A save is
content/<XUID>/<title id>/00000001/<save>/..., with its header file at<title id>/Headers/00000001/<save>. The tree can sit undercontent/,Content/or nothing, and the XUID folder can be left out. The donor's XUID is replaced with the signed-in profile's. - The title is the one in the member's path, and must be the game being
launched. The launched game is named by the rom's own folder, when it is
laid out as
<title id>/000D0000/<package>or<title id>/00007000/<package>, or by RomM'stitle_id. With neither it isidentity_unknown, and another game's title isidentity_mismatch. - A profile package,
FFFE07D1, isprotected_destination, whether or not a profile is signed in. Any other content type, DLC and updates included, isunrecognised_layout, and so is a file where a save folder belongs. A save that is one STFS package file rather than a folder isshape_unverified. A RetroArch.srmissource_incompatible.
shadPS4 files a save under the default user, whichever user it was collected from:
- A save is
<serial>/<save dir>/<files>, optionally undersavedata/orhome/<n>/savedata/, where<n>is a number. The serial, such asCUSA12345, is four letters and five digits in either case, and is upper-cased. Everything below it is kept as sent. - The serial must be the launched game's when the session names one.
The broker reads
TITLE_IDout of the rom's ownsce_sys/param.sfo, the file shadPS4 itself names a save folder for, and falls back to RomM'stitle_id. Another game's serial isidentity_mismatch, since the exit dump ships the whole savedata subtree and would carry it into this rom's archive. A.pkg, a.zaror an archive is still packed when the import is checked, so a launch of one is compared against RomM'stitle_idalone; a launch with neither takes a save without comparing it. - The
param.sfois only read when it is a regular file resolving inside the ROM library root, so a library that carries a symlink out of the tree, or a named pipe, names no serial rather than reading a host file. - A save that names no serial, or one of the wrong length, is
identity_unknown.sce_sys/corrupted, the marker shadPS4 leaves while a save is mounted, isprotected_destination.config.json,extracted/andsys_modules/, another folder underhome/<n>/, and ahome/<name>/whose name is not a number areunrecognised_layout. So are a loose file and a serial with no save folder and file below it. A flat.srmissource_incompatible. - Two users' copies of one save are a
destination_conflict, since they land in the same folder. A name too long for the filesystem isunsafe_path.
Flycast, DuckStation and RPCS3 have no mid-session save states, but each boots
straight into a state the archive carries, the same way it resumes the one
it writes on exit. PPSSPP, Dolphin and ScummVM do have them, and resume a state the
archive carries the way they resume one pushed after activate. So all six
answer state_channel: "archive", take at most one state counting any the
archive already holds, and need discovery's state_slot sent as
save.resume_slot. An archive that already holds a state of its own refuses
an imported one as destination_conflict, so leave the old state out to send
a new one. An undo buffer is not a state and does not count: PPSSPP's
*.undo.ppst and load_undo.ppst, or Dolphin's lastState.sav. PCSX2
answers state_channel: "push", and so does RetroArch on a platform whose
core has states.
Flycast and DuckStation name no card_subtree: their cards are ordinary
save files, restored with the rest of the archive. PPSSPP has no memory card
and names none, and neither do Dolphin on wii, RPCS3, ScummVM or RetroArch. Dolphin on ngc names
GC, and PCSX2 names memcards. When the session syncs that card on the
memory-card routes, a member that would land on it answers
memcard_synced_separately. Otherwise an imported card, or a GCI, in an
archive that already carries a card there is a destination_conflict.
Refusal reasons
manifest_invalid
The archive holds .import/ members but no usable version 2 manifest, or a
member is undeclared, declared twice, declared but absent from the archive,
declared with a kind other than save, state or memcard, or declared as
a kind that does not match its path.
unsafe_path
A path component is empty, hidden, .., __MACOSX or too long, or the name
has a backslash, colon, control character or bidirectional control
character, or it is non-ASCII without the zip UTF-8 flag. Also used when the
archive holds the same name twice, and when the destination would resolve
outside the save root through a symlink.
unreadable_member
The broker cannot read the member: it is encrypted, it uses a compression
method other than stored or deflate, or its data is corrupt (it fails its
CRC check or will not decompress). Bzip2 and lzma members are refused
outright rather than decompressed: zipfile's reader for both has no cap
on a single call's output, so a small compressed member can expand to an
unbounded amount of memory before anything checks a size limit. A regular
member outside .import/ whose timestamp is invalid is refused with this
code too. The
check runs on every member the restore will write, before the working slot
is cleared, so a corrupt member never costs the player the save they already
had.
A member can also be refused this way once the checks read into it: an
emulator that reads a member to place it, as Dolphin reads the id a state or
a GCI opens with, or to check the archive's imports as a whole, refuses one
whose data turns out to be corrupt, with the detail
the member's data is corrupt.
kind_not_accepted
This emulator does not take this kind. expected lists the kinds it does.
state_uses_push
This emulator takes states through PUT /api/session/state-file after
activate, not inside the archive.
resume_slot_required
The state only loads when save.resume_slot is set on the activate.
memcard_synced_separately
The memory card travels on the memory-card routes this session, so it cannot also come in through the archive.
source_incompatible
The member is in a format this emulator cannot read, such as a RetroArch
state given to a standalone emulator. suggest_emulator names one that
can, when there is one.
needs_conversion
The data is right but in a container this emulator does not read directly.
unrecognised_layout
The member's path does not match any shape this emulator accepts. When the
member's origin is emulatorjs or hardware, the refusal becomes
source_incompatible instead, with a note on the origin after the detail.
shape_unverified
The shape is recognised, but loading it is unproven or blocked by a known broker limit, so the broker refuses rather than place a file that silently won't load.
A PCSX2 folder card without _pcsx2_superblock is refused this way. So are
an Xbox 360 save that is one STFS package file, a 3DS save manager's JKSM or
Checkpoint backup folder, a RetroArch GameCube save, and a RetroArch 3DS
member that is not in one of Azahar's save folders.
incomplete_unit
A save that spans several files is missing one, or a file is empty: a PSP
or PS3 save folder without its PARAM.SFO, a PPSSPP screenshot sent without its
.ppst, a PCSX2 card whose _pcsx2_superblock is empty, or an Eden account
save sent without a profile store. When other
members were also refused, a missing-file detail says this may be a knock-on
effect of those refusals.
destination_unresolvable
The emulator cannot work out where this member belongs for this rom. On Eden,
a save collected by JKSV or Checkpoint, or as a folder that starts with a
title id, has no save space or profile in its path. On Azahar, a loose file
or bare data/ folder names no title, when RomM knows the game. On Xenia,
the config names no single signed-in profile.
identity_unknown
The emulator needs to know which game this is, and neither the rom nor RomM says. ScummVM refuses a save this way when it detects no game in the rom folder, and RPCS3 a state when the boot target carries no title id. For Xenia, neither the rom nor RomM names the title; for xemu, the disc's own certificate does not, whatever RomM sends; for Cemu, neither does when the member's path names no title; for shadPS4, the member's path names no serial.
identity_mismatch
The member belongs to a different game than the one being launched. When
RomM supplied the session's id, the detail says how to correct it. Cemu,
Eden, Azahar, shadPS4, xemu and Xenia check a save's title this way; Cemu,
Eden, Azahar and shadPS4 check only when the session names a game at all,
which for shadPS4 means the rom's own param.sfo or RomM's title_id.
protected_destination
The member would overwrite emulator configuration, not save data, or data the
console owns. Examples are Cemu's account store, Xenia's profile package, 3DS
sysdata, the mount marker shadPS4 leaves in a save, an RPCS3 licence, trophy
or EBOOT, and a Wii system title.
destination_conflict
Two members land on the same file, a member lands where a restored save already goes, or there are more members of a kind than the emulator allows. Cemu refuses an archive that holds saves for two donor accounts this way, and Eden refuses an imported profile store when the archive already carries one.
too_large
The archive, imports included, is over the size or file-count limit.