Quick answer: Corona SDK, now the open-source Solar2D, builds Lua games that compile to iOS and Android, where an uncaught Lua error crashes the app on a player's phone. Hook the runtime unhandledError listener, wrap risky logic in pcall to capture tracebacks, attach device and platform context, and group identical Lua errors into one dashboard issue.
Corona SDK was a popular cross-platform Lua framework for mobile games, and it lives on as Solar2D, the open-source continuation with the same Lua API and display object model. You write Lua, the framework compiles to native iOS and Android apps, and your game runs on a player's phone where you have no terminal and no console. An uncaught Lua error, a nil index, a bad string format, a call on a missing method, crashes the app, and the player simply sees it close. This post covers how Corona and Solar2D errors surface on mobile and how to capture Lua tracebacks and device context so those silent closes become fixable reports.
How Lua errors crash a mobile build
Corona and Solar2D run your Lua on a runtime embedded in a native app, driving the game through enterFrame events and timers on the display objects you create. When your Lua throws an uncaught error, the framework's default behavior on a device is to terminate the app. The most common sources are indexing a nil field on a table, arithmetic or concatenation involving a nil value, calling a method that does not exist on a display object, and errors inside event listeners that the runtime invokes for touch, collision, or timers.
On your development machine the simulator prints these errors with a Lua traceback you can read, which lulls you into thinking they are visible. On an actual iOS or Android device there is no such output reaching you; the app just closes, and the player moves on or leaves a one-star review saying it crashes. The Lua error and its traceback exist at the moment of failure, but without deliberate capture they die with the process on a phone you will never hold.
The unhandledError listener
Corona and Solar2D expose a global safety net through the Runtime unhandledError event. By adding a listener for unhandledError, you receive the error message and the stack traceback for any Lua error that would otherwise crash the app, and you can return true to indicate you handled it, which lets you report and optionally keep the app alive rather than terminating. This single listener, registered at startup before your scenes load, is the backbone of crash capture for these frameworks because it catches errors from anywhere in your Lua, including inside framework-invoked event callbacks.
The event provides the error string and a traceback that names your Lua files and line numbers, which is genuinely useful for jumping to the fault. Register the listener as early as possible in main so that even errors during initial scene setup are caught. Returning true keeps you in control of what the player sees, letting you show a graceful message or attempt to return to a safe scene instead of a hard crash. This listener is the difference between learning about device crashes and never hearing about them.
pcall for risky sections
The unhandledError listener catches what escapes, but for code you know is risky, wrapping it in pcall gives you finer control and better tracebacks. pcall runs a function and returns a status and the error if it failed, so you can capture the failure with surrounding context, the current scene, the object involved, and recent state, before deciding to recover. Pairing pcall with the Lua debug.traceback function yields a full stack at the point of failure rather than just the top-level message, which sharpens reports for deeply nested logic.
Use pcall around areas where an error is plausible and recovery is meaningful: parsing saved data that may be corrupt, loading remote content, or third-party plugin calls that can fail on some devices. For these, a captured error you can recover from is far better than an app termination. Reserve the unhandledError listener as the catch-all for the unexpected, and use pcall as the targeted tool for the known-risky. Together they give both broad coverage and detailed, context-rich capture where it matters most.
Device and platform context
Because Corona and Solar2D target both iOS and Android, the platform field is essential. Use the system functions to capture the platform name, the OS version, the device model, and the app build version, since a crash that only hits older Android versions or one device family is common and invisible without these fields. Memory matters too: mobile games get killed under memory pressure, and a crash that is really an out-of-memory termination needs memory context to be recognized as such rather than chased as a logic bug.
Add gameplay context that maps to your structure. Corona and Solar2D games are usually built from scenes via the composer or a similar manager, so record the active scene name, which immediately narrows a crash to a screen. Capture a short breadcrumb of recent actions, the last touch or timer event, and the session length. With platform, OS, device, and scene attached, a captured Lua error stops being a bare line and becomes a record you can place precisely, telling you both what failed and on which kind of phone it failed.
Setting it up with Bugnet
Bugnet fits Corona and Solar2D because your capture points, the unhandledError listener and your pcall handlers, are clean places to send a report. In the listener, hand Bugnet the Lua error message, the traceback, and a context table with the active scene, platform, OS, device model, and app version. The crash arrives as a readable Lua traceback with your files and lines, plus the mobile fields that tell iOS and Android, and old and new OS versions, apart. You can also add an in-game report button to a scene so a player can flag a non-fatal glitch while the current scene and state are captured automatically.
On the dashboard, Bugnet groups identical Lua errors into one issue with an occurrence count, so the same nil index across thousands of installs is a single ranked item rather than a stream of mystery closes and bad reviews. Custom fields for platform, OS version, and device model let you filter instantly: if a crash is Android only, or confined to one OS version, the grouped view makes it plain. For a mobile Lua game where every crash is otherwise a silent app close, that grouping is what converts an invisible problem into a prioritized fix list.
Testing on real iOS and Android devices
The simulator is convenient and misleading. It runs on your fast desktop with ample memory and a forgiving environment, so memory-related crashes and platform-specific quirks frequently appear only on real phones. Build your unhandledError listener and pcall handlers, then deliberately trigger a Lua error on an actual iOS device and an actual Android device, confirming each reports with the right platform tag, traceback, and context. Test under low-memory conditions, since out-of-memory kills are a top cause of mobile crashes the simulator never reproduces.
Make device testing part of every release across both platforms, not an occasional check. Corona and Solar2D make it tempting to validate only in the simulator because builds are quick, but your iOS and Android players crash differently and silently. With the unhandledError listener proven on hardware, pcall guarding the risky paths, and crashes grouped and tagged by platform and device, your post-launch view becomes one prioritized list. You fix the Lua error hurting the most players first instead of guessing from a one-star review that just says it crashes on my phone.
Corona and Solar2D crashes are silent app closes on a phone. Hook unhandledError, capture the traceback, tag the platform, and grouping turns one-star reviews into fixes.