Troubleshoot function execution and logs
Find the cause when a function never runs, stops before it responds, or produces no log output, and apply the fix.
A function created with Functions can fail at instantiation, at invocation, or during execution. Without log output, you cannot tell which. Each section below names one symptom, gives its cause, and states the fix. Start with the logs.
No log output from a function
You call console.log in the function, and no message reaches you.
A function writes log messages with console.log, the same way JavaScript does in a browser. Azion collects that output and delivers it in three places: Azion CLI, Data Stream, and Real-Time Events. Until you open one of them, a function that fails and a function that never runs look the same.
First, confirm that the code logs something. This handler logs a message and returns a response:
To read the output from the terminal with Azion CLI:
The terminal prints the console messages of the last 5 minutes and keeps printing new ones. Add --function-id to restrict the output to one function. The subcommand is named cells because a function runs inside a Cell, the isolation environment Azion builds on V8 isolates.
To send the same output to an endpoint you own:
Access Azion Console > Data Stream.
The stream sends the log messages of your functions to that URL.
The Functions Event Collector template fills the Data Set box with this preset:
| Variable | Definition |
|---|---|
$time | Date and time of the request. |
$client | Unique Azion customer identifier. |
$global_id | Settings identification. |
$edge_function_id | Function identifier. |
$request_id | Request identifier. |
$message_source | The source of the message. |
$log_level | Level of the log created: ERROR, WARN, INFO, DEBUG, or TRACE. |
$log_message | Message used on the log when the function is requested. |
To read the same output in Azion Console:
Access Azion Console > Real-Time Events.
The Functions Console tab lists one entry per log message, with its level, its line, and the identifier of the request that produced it.
The function never runs
The function exists in Functions, and no request executes it. Nothing from its console.log calls reaches the function logs.
Creating a function does not execute it. A function runs when an application instantiates it and a Rules Engine rule selects that instance through the Run Function behavior. Without both, the code never executes.
Check the chain in order:
- Functions module: in the Main Settings tab of the application, turn on Functions, then select Save.
- Function instance: in the Functions Instances tab, select + Function Instance, select your function, and set its Args. The instance binds the function to the application and carries the JSON arguments passed to its execution context. Refer to Function instances.
- Run Function rule: in the Rules Engine tab, add a rule, set its criteria, and select the Run Function behavior with your instance.
- Rule criteria: a rule executes its behaviors only when the request meets its criteria. Compare the criteria against the URI you request.
- Behavior order: Deliver, Deny (403 Forbidden), and Finish Request Phase end the processing of a request. A Run Function arranged after one of them never executes. Move it above the behavior that finishes the request.
The next request that meets the criteria executes the function, and its messages reach the function logs.
Run Function is missing from the behaviors list
You add a rule in the Rules Engine tab of an application, and Run Function is not among the behaviors.
The Run Function behavior depends on two modules: Application Accelerator and Functions. While Application Accelerator is turned off, Rules Engine offers only part of its variables and behaviors.
To turn on both modules:
Access Azion Console > Applications > your application.
Run Function appears in the behaviors list of a rule, in the request phase and in the response phase.
The function fails at instantiation
The function instance carries a large Args object, and the function fails at instantiation.
Args is the JSON object a function instance passes to the execution context of the function. The field accepts a maximum of 100 KB. Arguments above that size make the function fail at instantiation.
- Trim the Args object: reduce the JSON until it is under 100 KB.
- Request a higher limit: the 100 KB is a default. To raise it for your plan, contact technical support.
With the arguments under 100 KB, the instance saves and the function receives the object in its execution context.
The function stops before it returns a response
The function starts, and the invocation ends before the code returns its response.
One invocation runs inside three ceilings, and a fourth bounds the execution context that carries it:
- CPU execution time, 2 s: the maximum CPU time per invocation. It measures active computation, not wall-clock time, so time spent waiting on
fetch()does not count against it. A function that exceeds it is terminated. - Execution time, 5 min: the maximum wall-clock time for one invocation, including I/O wait,
fetch()calls, and async operations. - Sub-requests, 50: the maximum number of outbound
fetch()calls in one invocation. - Memory per isolate, 512 MB: the maximum memory for a single execution context (V8 isolate), including heap, stack, and all runtime allocations.
Reduce the work the invocation performs:
- Find where the pressure sits: a function that spends its run waiting on an origin stays far from the CPU ceiling, however long the request takes. A function that parses or transforms a large body on every request spends that budget instead.
- Move work off the response path: work whose result the response does not need is handed to
ctx.waitUntil(), which extends the lifetime of the function past the response. That takes the work off the response path without taking it out of the invocation. The 5-minute wall clock still bounds it. - Consolidate the outbound calls: a design whose call count grows with its input, one request per item in a list, crosses the sub-request ceiling as soon as the list passes 50 items. Replace one call per member with one call that returns the set. That trade has its own boundary: the body a function can process is capped by plan, at 100 MB on Hobby, 200 MB on Pro, and 500 MB on Enterprise.
- Request a higher limit: every ceiling is a default. To raise one for your plan, contact technical support.
For the complete set, refer to Limits.
A function whose work fits inside the CPU and wall-clock ceilings runs to the end and returns its response.
ERROR entries in the function logs
The function logs carry entries whose level is ERROR, such as TypeError: Object not found.
Every log entry carries a level and a line source. CONSOLE marks a line your own code wrote with console.log. RUNTIME marks a line Azion Runtime produced, such as an exception raised while the function executed.
- Read the whole request: the request identifier aggregates every message from a single request. Filter on it to see what the function logged before the error.
- Query the events: the
functionConsoleEventsquery returnslevel,lineSource, andlinefor a time range. Refer to Query function logs with GraphQL API. - Filter in Azion Console: the Functions Console tab of Real-Time Events shows the same fields with filters.
You now have the exception message and the identifier of the request that produced it.
The preview renders nothing
You open Preview deployment for a function, and no response appears next to the code editor. The preview shows a warning that names the missing function.
Preview deployment renders the outcome of an auxiliary function in your source code, called PreviewProvider. That function builds a simulated request and hands the result to the preview. Without PreviewProvider, the preview has nothing to render.
- Add the
PreviewProviderfunction: it creates the request the preview sends to your handler. Refer to Preview deployment. - Debug the running function with
inspect: theinspecttool inside Preview deployment shows the behavior of the function in real time.
The preview renders the response next to the code editor, and the open button shows it in a separate tab.