Skip to content

Troubleshooting

Start with:

Terminal window
npm run doctor

It checks killscript.config.json, entry files, both TypeScript contexts, compiler output and the saved game link. Fix the first reported error before changing generated files or reinstalling packages at random.

The game cannot load the TypeScript project directory. It needs the generated folder directly under Modules:

Modules/
└── MyModule/
├── module.json
└── scripts/main.lua

Run:

Terminal window
npm run install:game -- --modules "/path/to/KILLSCRIPT/Modules"

Open or reopen the in-game module list and enable MyModule once. If the list was already open and does not rescan, restart the game once. Future npm run dev builds keep the same module UUID and update this folder in place.

A .KillScript file is a packaged module with the same internal structure, not a standalone Lua text file.

A build succeeds but no module log is visible

Section titled “A build succeeds but no module log is visible”

Open the game console with ~. Near the search field, use the filter icon to enable the category containing module output. Engine, network and voice logs can otherwise hide a correct module entry.

Add one unmistakable startup line while diagnosing:

import { logger } from "@killscript/sdk/client";
logger("Startup").info("client bundle loaded");

Remove noisy temporary diagnostics after the issue is found.

Confirm that npm run dev is still running and that the latest save says it was synchronized. A failed compile deliberately leaves the previous working module installed.

If only Reflex behavior is stale, make sure scripts/server.lua actually changed. The CLI prints a server reload notice for a real change. Toggling the module from the list may restart only the client in some game builds.

Run npm run dev -- --once to turn the next build into a single command with a clear success or failing exit code.

Keep dev running: it retries transient locks. A failed build never starts a sync; if a sync fails while replacing a file, that file is restored. The whole folder update is not one transaction, so files replaced earlier in the same sync may already contain the new build.

  • edit TypeScript in the project, not generated Lua on the mounted share;
  • close tools holding a generated file open;
  • verify that the SMB mount is writable;
  • run npm run doctor to confirm the saved target path.

The synchronizer prefers one overwrite-rename. On filesystems that reject it, the recoverable backup fallback can create a very short replacement gap.

Use static relative imports without an extension:

import "./features/feature";

Implementation imports must remain inside src/. Client code cannot import server implementation files and vice versa. Runtime npm packages are rejected; move small runtime helpers into src/ or use a type-only package.

Do not call Lua require() yourself. The compiler bundles nested files because the game’s custom loader only resolves top-level module paths reliably.

A global or method is missing in TypeScript

Section titled “A global or method is missing in TypeScript”

Check the current file’s context. Cameras, controls, UI, audio and visuals are client-only. A Reflex file receives server declarations instead. Move the code to its owner and exchange plain state through typed networking when both sides are involved.

If the member is public and documented for this context but absent from the types, report it as a declaration coverage bug rather than using any.

The CLI refuses to overwrite or remove a folder

Section titled “The CLI refuses to overwrite or remove a folder”

The target has a different module UUID or is not managed by this project. This is a safety check.

  1. inspect the folder and confirm which module owns it;
  2. choose another module name in killscript.config.json, or remove the conflicting folder yourself after checking it;
  3. run npm run install:game again.

killscript clean --game also removes only a folder whose ownership can be proven.