system.pathForFile returns nil for ResourceDirectory subdirectories with custom keystore (works with debug keystore)

I have a Solar2D app (build 2026.3729) that uses Lua modules organized in subdirectories:

src/
├── main.lua
├── services/
│ └── myservice.lua
└── libs/
└── mylib/
└── src/
└── calculator.lua

In myservice.lua, I set up package.path to load from the subdirectory:

local libPath = system.pathForFile(“libs/mylib/src”, system.ResourceDirectory)
if libPath then
package.path = libPath .. “/?.lua;” .. package.path
end
local calc = require(“calculator”)

This works perfectly with the debug keystore on an Android device (Samsung S24 Ultra, Android 16).

When I build with a custom release keystore (same build.settings, same code, same Solar2D build), system.pathForFile returns nil for the
subdirectory path, and require fails:

module ‘calculator’ not found:
resource (calculator.lu) does not exist in archive
no field package.preload[‘calculator’]
no file ‘(null)/calculator.lua’

I also tried resolving via a known file and stripping the filename:
local file = system.pathForFile(“libs/mylib/src/calculator.lua”, system.ResourceDirectory)
This also returns nil with the custom keystore.

I also tried relative paths in package.path:
package.path = “libs/mylib/src/?.lua;” .. package.path
The paths appear in the search list but the files are not found in the archive.

Questions:

  1. Why does system.pathForFile for ResourceDirectory behave differently with debug vs custom keystore?
  2. Is the APK asset compression different for release/custom keystore builds?
  3. What is the recommended way to require Lua modules from subdirectories that works on both debug and release Android builds?
  4. Is using dot-notation require(“libs.mylib.src.calculator”) the only reliable approach? (The library has internal requires like
    require(“utils”) that would all need to be changed.)

Environment:

  • Solar2D build: 2026.3729
  • Device: Android 16 (Samsung)
  • Same build.settings for both builds
  • No excludeFiles configured

AFAIK, 1-2 there shouldn’t be any difference, unless the buildtype is set to debug or release.

Make sure you understand the limitations of Android APKs in this context, see system.ResourceDirectory.

Try adding the “.txt” extension in both cases to see if it works; If not, please provide a minimum demo or an official sample so that others can quickly test and identify the issue.

3-4 We do the same thing, I don’t think there’s a problem.

I’m still mystified what role the keystore might play in this. (I don’t mean your assessment, just the situation.) It’s possible, though I’d have to investigate, that the build is a bit more casual about packing stuff up in that scenario, and so keeps the Lua source files around, versus stuffing only their bytecode-compiled versions around (“but the files are not found in the archive”). I might be deep in the weeds with that stuff shortly, in which case I’ll try to follow up. (This might explain the luaproc details—it seems related—though I might expand on that later too.)

Could it be that you made a Live Build with your debug keystore? I think the .lua files exist as is on live builds and Live Builds only support debug keystores on Android.

Please see this minimal test case to replicate the issue. Having issues uploading files. Please use the 3 files in the root and the code for the helper.lua file in a utils subdirectory.

main.lua (5.5 KB)

config.lua (117 Bytes)

build.settings (280 Bytes)

helper.lua

– Simple test module in a subdirectory (utils/helper.lua)
– Required as: require(“utils.helper”)
– On release keystore, workers can’t resolve this without Solar2D’s archive loader
local M = {}

function M.greet(name)
return "Hello from mymodule, " .. tostring(name) .. “!”
end

function M.add(a, b)
return a + b
end

return M

I downloaded the files and tested on my Android device. I tested a regular (non-live) debug build and the files are not there either, confirming the keystore is not the variable.

I traced the Android build related code and it just seems that for all regular Android builds, debug and release, the .lua/.lu files are compiled to bytecode and they’re stored inside resource.car with the flattened dot-notation names.

The only instance where I can see that .lua files could be found on your Android builds is if you’ve created a live build, in which case the files would be accessible and they’d be constantly synced between your computer and device. If you make a non-live build using debug keystore, then you should not be able to find those .lua files on the device.

If you have .CoronaLiveBuild in your project’s root folder, then you’ve made a live build at some point. It’s possible that when you’re making debug builds, there’s some cache issue and the files are found, or the modified .main file used by live builds connects to your computer and the files appear because of that.

I thought perhaps it could have had something to do with neverStripDebugInfo being set to true in build.settings, but that’s not something that would flip dependent on keystore (unless you have a build script that does something like this). Even then, I’m not sure if it leaves the lua files as they are or still put them into resources.car but without turning them into bytecode.

Ah, thanks for looking into it. So it is a generic problem to overcome in any building if you want to do that.

The solution that finally works for me is to bundle the files myself into 1 lua file.