Build and Runtime Troubleshooting
Use this page when the editor validates incorrectly, the PS1 build fails, or the runtime reports a load error.
Fast Triage
- Run Build > Validate Project.
- Open Problems and fix hard errors first.
- Open Build > Tools & Diagnostics > Show PS1 Budget and inspect hard limits.
- Check Build/ps1/logs/ after a failed build.
- Inspect Build/ps1/disc_root/DATA/MANIFEST.JSN when a runtime asset cannot load.
- Test the generated
.cuefromBuild/ps1/package/.
Common Build Issues
| Symptom | Likely cause | Fix |
|---|---|---|
| Missing runtime compiler tools | Private/source build selected without its toolchain | Use the installed binary runtime or open Build > Tools & Diagnostics > Tool Paths... |
| Missing Ninja path | Private/source runtime build selected without its build runner | Configure Ninja for that source build; binary releases use the bundled runtime |
| Missing mkpsxiso path | Tool path not configured | Set mkpsxiso executable path |
| Build & Run fails | DuckStation path missing or invalid | Configure DuckStation path |
| Sticks do not move the player or camera | Analog mode is off or the emulator has no Port 1 stick mapping | Configure Port 1 as Analog Controller / DualShock and enable Automatically Enable Analog Mode, or press the mapped Analog/Guide button. Last Exit also supports the D-Pad and L1/R1/L2/R2 in digital mode. |
| Camera or player moves without touching the sticks on a physical PS1 | Resting stick values exceed the configured dead zone; an emulator may return a more precise center | Start with PlayerInput > Dead Zone = 0.35. In Last Exit, set the player LuaBehaviour's deadZone to 0.35. Rebuild the game; updating the editor alone does not change an existing project or disc. See Input. |
| Startup scene missing | Build Settings points to a missing scene | Open Build > Build Settings... |
| Scene load fails at runtime | Scene not included in Scenes In Build | Add the scene to Build Settings |
| Repackage Disc (Reuse Runtime) fails | No available runtime or stale staged files | Run full Build Disc Image (.bin + .cue) |
Model import reports collapses at PS1 vertex precision | Small details lose their area during PS1 coordinate conversion | Recenter or split the source mesh, simplify very thin details, and reimport. See Model Import. |
Texture import reports invalid image size | The source image is invalid or too large to decode safely | Resize or re-export the original image in a supported format, then use Apply & Import. |
Needs optimization or a tight main RAM margin | A PS1 production target is close to its limit; this is separate from your PC's memory | Open PS1 Budget from the warning. Check the exact free bytes, reduce resident mesh/animation data or split the scene, then rebuild. See Understanding warnings in Problems. |
Runtime Load Errors
failed to load MANIFEST.JSN
Check:
Build/ps1/disc_root/DATA/MANIFEST.JSNexists,- packaging completed successfully,
- the
.cuepoints to the expected.bin, - the runtime is launched from the latest build output.
Missing script or script load error
Check:
- the Lua Behaviour Script field points to an existing
.luafile, - the script is under the project and staged into compact runtime folder
DATA/L, - the script does not exceed the configured size limit,
- the target callback function exists if a UI button or Interactable calls it.
Missing mesh, texture, material, or audio
Check:
- the asset exists in
Library/asset_db.json, - the source asset still exists under
Assets/, - the imported output exists under
Library/, - the staged file exists under the compact
Build/ps1/disc_root/DATAruntime folders (S,L,M,R,T,A, orX), - Validate Project does not report missing GUIDs or files.
Streaming music does not play
Check:
- the source WAV has Streaming Music (CD-XA) enabled,
- no more than 8 streaming tracks are enabled,
Build/ps1/disc_root/DATA/X/contains the encoded track,- the name passed to
Music.Play()matches the WAV filename stem; comparison is case-insensitive, - the script checks the boolean returned by
Music.Play().
Gameplay Issues
| Symptom | Check |
|---|---|
| Player walks through an object | Object has Collider, Collider is not trigger, Level Builder placement created collider |
| Trigger does not fire | Collider exists, Is Trigger is enabled, and the Lua Behaviour defines OnTriggerEnter |
| Interact does nothing | Player has Interaction Ray, target has Interactable, and the configured function name matches exactly |
| UI button does nothing | Button On Click target GameObject/function is set and the Lua Behaviour defines that function |
SceneManager.LoadScene() does nothing | Target scene path is correct and included in Build Settings |
| Audio sounds distorted on PS1 but clean in Play Mode | Rebuild with the current editor so older WAV imports are regenerated. If needed, select the source WAV and use Reimport, then build a new disc image. Also check Audio Source Volume or Music.SetVolume and avoid clipping in the source WAV. |
| Audio does not play | GameObject has Audio Source, clip GUID exists, and the resident clip fits the SPU budget |
| Music does not play | Streaming flag is enabled, track is staged in DATA/X, and Music.Play() uses the source filename stem |
| Save fails in DuckStation | Enable a writable Memory Card in Slot 1 with one free block; read SaveData.GetLastError() immediately after failure and retry. Wait for card access to finish; CD-XA music pauses and restarts during the operation. |
| Save/load does not persist | Use PlayerPrefs.Save() for typed preferences or SaveData.Flush() for raw values; use SaveData.Reload() before expecting fresh device data |
| Game uses the wrong refresh rate | Select NTSC or PAL under Project Settings, save, then run a full Release build instead of Repackage Disc (Reuse Runtime) |
| Progress Bar does not change | Resolve it with UI.Find(), then check the boolean returned by ProgressBar.SetValue() |
| Navigation destination returns false | GameObject has an enabled root NavMesh Agent, referenced surface exists, preview bake has a connected path on that surface, and the complete route fits within 32 points |
| Agent crosses a dynamic obstacle | Runtime navigation has no dynamic avoidance; use authored colliders in the bake or stop/replan from script |
| Portal room disappears | Renderer Room assignment, camera inside expected Room, Portal enabled/open and direction/two-sided state, non-zero opening size, and valid Portal transform |
Timeline.Play() returns false | Clip name matches exactly and the clip exists in the active scene |
| Native player still moves in a cutscene | Enable Disable Player Controls on the clip; custom Lua movement must be gated separately |
| Rumble is unavailable | Use Rumble.IsSupported(); verify an analog/DualShock pad, DuckStation vibration mapping, and that the active BIOS handler supports the fail-closed optional output patch |
Rendering and Performance Issues
| Symptom | Check |
|---|---|
| Faces disappear or fold when the camera turns | Rebuild with the current runtime and compare the same view in Game preview and the packaged CUE. Check source winding, duplicate/intersecting faces, camera collision and near-plane placement; do not flip UVs or make every material double-sided. See Model Import. |
| Polygons overlap incorrectly | Check coplanar duplicates, embedded decorations and transparent surfaces. Automatic boundary ordering and subdivision reduce artifacts but do not supply a depth buffer. See Rendering and Level Authoring. |
| Walls look coarse while small props look detailed | Compare imported dimensions and atlas space per surface. Correct UV proportions and texel density in the source model; increasing palette size alone adds no pixels. See Texture Import. |
| Scene is slow | Triangle count, packet estimate, texture count, audio clips, active scripts |
| UI draws over world unexpectedly | UI element sort/order and foreground OT reservation |
| Transparent object sorts badly | Keep transparent surfaces small and isolated |
| VRAM packing conflict | Open VRAM Inspector, select the red region, reveal the texture, then change format/size and reimport |
| Mesh colors are missing | Imported mesh contains vertex colors and Mesh Renderer uses Mesh Vertex Colors |
| GTE lighting is flat | Mesh contains usable normals, scene lighting is active, and Mesh Renderer uses GTE Vertex Lighting |
| Distance fog band looks coarse | Increase geometry subdivision where a large triangle spans much of the fog range; PS1 fog is interpolated from per-vertex factors, not evaluated per pixel |
Low frame rate in DuckStation
- After updating the engine, run Build Disc Image (.bin + .cue) and open the newly generated
.cue. Repackage Disc (Reuse Runtime) can reuse a previously staged runtime; it does not replace a full rebuild. - Check DuckStation's Game counter. Video: 60 FPS (100%) describes NTSC output and emulation speed, not 60 game updates per second. Measure with CPU overclock disabled and normal emulation speed; enhancements such as PGXP do not establish original-hardware performance.
- Hold L1 + R1 and tap Select to show the runtime overlay. Its frame value counts VSync intervals per game frame: at nominal NTSC 60 Hz, 1 interval is about 60 FPS, 2 about 30 FPS, and 3 about 20 FPS. At PAL 50 Hz, the same intervals mean about 50, 25, and 16.7 FPS. The slow counter counts frames taking more than one interval; it is not an error count or a configurable 30 FPS target.
- Compare several views while moving through the level. If render time dominates, reduce simultaneously visible geometry, excessive subdivision, overlapping transparent surfaces, and distant detail. Use Rooms, Portals, and Navigation to organize interiors. If physics time dominates, simplify collision shapes and remove unnecessary overlapping Colliders. If Lua time dominates, avoid repeated scene searches and rebuilding strings or tables every frame; refresh HUD text only when its value changes.
- Rebuild and repeat the same route after each change. Check packet drops, allocation failures, and Lua errors as well as frame timing. Test loading and scene transitions separately from steady gameplay, then test with the overlay hidden too.
PS1 Ready and the documented triangle limits are budget checks, not a frame-rate guarantee. A larger level needs its own measurements; neither a small demo's result nor Play Mode performance predicts every game's speed. See PS1 Budget Dashboard for the counters and reports.
UI, loading and event audio
| Symptom | What to check |
|---|---|
| Item image overlaps storage rows | Check authored Enabled, parents, Canvas visibility and layout mode. Start an inspection preview disabled and enable it only in the intended view; changing text does not hide images. |
| UI image stays black or is missing on PS1 | Check the texture GUID, import output and scene dependency. A filename passed to Image.SetTexture is not a GUID. Reference dynamic choices in authored UI so the build loads them, including hidden elements. |
| Reticle has a solid rectangle behind it | Use transparent source pixels and Mask1Bit import; check whether a separate Panel supplies the background. |
| Dialogue stops revealing text or clips a sentence | Check Visible Characters, the 127-byte label limit, bitmap glyph coverage and rectangle size. Use the complete line for layout and change only its reveal count. |
| UI animation stops during pause | Enable the clip's Unscaled Time setting or use Time.UnscaledDeltaTime for a Lua presentation timer. Keep its Canvas enabled until the exit finishes. |
| Sound cannot be stopped, or IsPlaying is false while it is audible | Independent PlayOneShot voices are not tracked by that Audio Source. Use Play/Stop for door creaks and other sounds owned by an action. See AudioSource. |
| Navigation or footsteps repeat too rapidly | Trigger from selection changes or actual movement, not a held condition every frame. Check each playback result; overlapping one-shots can run out of voices. |
| Loading image appears after the first frame, or percent restarts | Art/font must be read before use, and progress describes the current read. Black presentation intentionally hides the regular UI. See Loading settings. |
| Reinstalling still opens an older demo | Update the editable example copy or create a fresh one; engine installation does not replace user projects. Rebuild and open its new CUE. See Updating the example. |
What to Save When Reporting a Bug
Include:
- project name and active scene,
- exact build command,
- Problems panel output,
- Console build/runtime logs,
Build/ps1/logs/ps1_budget_current_scene.json,Build/ps1/logs/build_summary.json,- relevant script file,
- screenshot or short video of the runtime issue,
- whether the issue happens in editor Play Mode, DuckStation, or hardware.
Script, memory, and loading problems
| Symptom | What to try |
|---|---|
Lua instruction budget exceeded | Check for unbounded loops and shorten callbacks or spread work across frames. Review Project > Project Settings... > Scripting > Lua VM Instructions / Callback. Raising Lua Heap (KB) does not fix an instruction limit. Reproduce the error in Play Mode for source-line diagnostics; normal PS1 exports use Release and strip that information. |
not enough memory or Lua heap exhausted | Lua has exhausted its configured memory pool. Check Project > Project Settings... > Scripting > Lua Heap (KB). For an older First Person Example still set to 64, use its updated 104 KiB preset, then Save, restart Play Mode and rebuild the disc for DuckStation. See the memory guidance below. |
Script exceeds max script size | Check Max Script Size (KB) in the same settings section. This is a per-file limit, separate from the shared Lua heap. Reduce or split an oversized script; the engine cap is 64 KiB per file. |
| RAM budget exceeded after an update | Build again to refresh the report, then reduce scene or asset size using the Budget Dashboard. Check scene transitions as well as individual scenes. |
| Music restarts after loading | XA playback resumes from the beginning of the track. Plan transitions with that behavior in mind. |
| Diagnostic text disappears | Check packet-drop counters in the runtime overlay and reduce geometry or UI load. |
| Saving or loading fails | Open Save Data Simulator, check the selected failure mode, and inspect SaveData.GetLastError(). Show a failure message and a retry option in your game. |
Adjusting Lua memory
PlayStation has 2 MiB of main RAM for the entire game: executable code, scene data, meshes, loading buffers and Lua all share it. This is not a 2 MiB allowance for scripts. VRAM and sound RAM are separate pools.
Lua Heap (KB) reserves memory for the Lua VM, its libraries and all active scripts, including their tables, strings and temporary allocations. It is shared across scripts, not assigned to each one. The editor uses KB for units of 1,024 bytes (KiB). On 64-bit Windows, Play Mode reserves twice the configured physical heap to accommodate larger pointers and allocation headers. This preview allowance does not change the exported PS1 budget, and Play Mode memory figures are not console measurements.
- Stop Play Mode and open Project > Project Settings....
- Under Scripting, check Lua Heap (KB). The supported range is 64–512 KiB. Keep the budget supplied with your example: First Person Example uses 104 KiB. Other projects may need a different value; increasing it also reduces the RAM available to the rest of the game.
- Click Save, then start Play Mode again. To test in DuckStation, rebuild the disc; an existing build keeps its previous settings.
- If it still runs out of memory, review allocations and retained data. Avoid rebuilding tables or strings every frame and loading large amounts of script data at once. Increase the heap gradually only while the overall RAM budget allows it, then review Budget Dashboard and the rebuilt project's reports. A setting of 256 KiB can leave too little RAM for a scene that fits with a smaller Lua heap. At 512 KiB, reduce script memory use rather than raising the setting beyond the engine limit.
A memory error can happen while loading a scene, before any Update callback runs. Shortening callbacks alone will not fix an undersized heap. An instruction-budget error, on the other hand, measures execution work rather than memory use.
The Console identifies the script and entity that failed. Play Mode pauses automatic retries for a failed load or frame callback; edit the script, assign a different script or restart Play Mode to retry. A changed memory setting requires a restart. Check scene transitions as well as initial loading, and test the rebuilt game in the emulator and on hardware: passing a budget report does not prove that every script allocation will fit.