lua test, workflow drivers, voice tests) see Test an agent before you release.
Verified against lua-cli 3.33.0.
Before you begin
- A project signed in with
lua auth configure;lua logsreads the agent inlua.skill.yaml(--agent-id <id>overrides it for another agent you administer). - Something to inspect: a conversation, a job run, a webhook call, or a workflow run that already happened.
1
Reproduce on an isolated thread
Send the smallest message that triggers the code path, on a fresh thread so earlier turns cannot influence the answer. The sandbox runs sandbox versions compiled from your local code; production runs the promoted version.When the bug is in one function rather than in the model’s decision, skip the conversation and call the function with
lua test skill --name <tool-name> --input '<json>'; its output is exactly what the tool returned, with no log lookup needed.2
Read the entries that run wrote
Filter by primitive type and, for skills, jobs, webhooks, processors, and devices, by name. Entries print oldest first.Each tool call writes
Output
Calling tool with input …, then Execute function completed in <n> ms and Tool result …, or an ERROR entry with the thrown message. Anything your code prints with console.log appears as a DEBUG entry and console.error as an ERROR entry, so log the raw return value of a platform call before you transform it and read its real shape here. A message field is stored up to 256 KB and then cut with [truncated; original length <n>].3
Widen or narrow the filter
--type accepts all, skill, job, webhook, preprocessor, postprocessor, device, device-trigger, user_message, agent_response, agent_error, mcp, rag, runtime, and calls. --name works with skill, job, webhook, preprocessor, postprocessor, and device. agent_error holds failures on the message path such as billing, validation, and model errors; runtime holds the agent runtime’s own lines; user_message and agent_response show what was said, with the channel and end user ID.--limit defaults to 20 and the server caps it at 100; use --page for older entries. There is no time filter and no environment filter: sandbox and production entries are stored together, and metadata.channel is dev for every message sent from lua chat in either environment, so bound a check by timestamp and, for one conversation, by --user-id. The flag table is on the lua logs reference.4
Script it with --json
--json returns { logs, pagination }. Each entry carries subType (error, warn, info, debug, start, or complete; there is no level field), message, an optional duration in milliseconds, and metadata with logSource, primitiveName, primitiveId, toolName, userId, and channel.Output
jq '.logs[] | select(.subType == "error")'.5
Debug the CLI itself
When a command fails, it prints one line, The exit code tells you the class of failure before you read the message; see Errors and exit codes.
✖ <code>: <message>, plus a 💡 hint. Set LUA_DEBUG=1 (or pass --debug to lua compile) to print the stack trace under that line.6
Verify a deploy
After
lua version promote or lua deploy, note the time, send one production message on a fresh thread, and confirm that nothing was written since under agent_error or as an error under skill. A throwing tool lands under skill, not agent_error, and the logs have no time filter, so the check reads both types and bounds them by timestamp.jq -e exits 1 when the filtered array is not empty, which is what a CI job needs; see Automate releases in CI.Options you may need
Read trigger, job, workflow, and call records
Some primitives keep their own execution records in addition tolua logs:
lua triggers logs shows up to 200 executions; lua jobs history shows the last 20 with status, duration, result, and error; lua workflows status --steps prints per-step state and output previews, lua workflows logs the run’s event stream (--follow keeps it open), and job-logs the container output of a Job-tier step. See the lua triggers, lua jobs, and lua workflows references.
Keep secrets out of the logs
The runtime’s own entries (runtime, workflow events, device command audits) redact bearer tokens, JWTs, and token=, api_key=, secret=, and password= values, and device command payload fields such as content and password are replaced with byte counts. Your own console.log output is stored as printed: do not log env('…') values or request headers. Local lua test runs write no server entries at all.
If it isn’t working
✖ usage: --type is required when using --name
✖ usage: --type is required when using --name
--name filters an entity list, so the CLI needs to know which list. Pass --type skill|job|webhook|preprocessor|postprocessor|device with it; message types (user_message, agent_response, agent_error, runtime, mcp, rag) have no names.✖ usage: lua: "mastra" is not a valid logs.type value.
✖ usage: lua: "mastra" is not a valid logs.type value.
The hint lists the accepted values.
--type all shows everything; runtime is the type for agent runtime and model-provider lines.✖ not_found: Skill "<name>" not found
✖ not_found: Skill "<name>" not found
Exit 3.
--name takes the primitive’s name as it appears on the server (lua skills view, lua jobs view, lua webhooks view), or its ID. For a skill it is the skill name, not a tool name.Next steps
lua logs reference
Every filter and the entry schema.
Test an agent before you release
Reproduce with exact input before reading logs.
Troubleshoot the CLI
Exact error strings by stage, with fixes.
About security and data
Where logs live and what is redacted.

