Skip to contentSkip to navigationSkip to topbar
Rate this page:
On this page

Functions and Assets FAQ



Why does my Function return 'runtime application timed out'?

why-does-my-function-return-runtime-application-timed-out page anchor

There are two likely reasons your Function has completed with the error: 'runtime application timed out'.

The most common reason is that your Function has exceeded the 10-second execution time limit. You can determine this by looking at the execution logs on the Function instance page. The last log line after execution will tell you how many milliseconds the Function took to execute. If the processing time is greater than 10,000 milliseconds, then Twilio terminated your Function.

Function timeout in logs.

The other, more subtle reason your Function ended with an application timeout is because of an incorrect invocation of callback(). If your Function does not call the callback() method or the method is unreachable, your Function will continue executing until it reaches the time limit and ultimately fails. A very common mistake is to forget to capture the catch() rejected state of a Promise and calling callback() there as well. The Function Execution documentation provides extensive details on the functionality and usage of the callback() method. Below are several examples of correct use of callback() to complete execution and emit a response.

Complete Execution with Asynchronous HTTP Request

complete-execution-with-asynchronous-http-request page anchor

Example of how to appropriately use callback() with an asynchronous HTTP request


_26
exports.handler = (context, event, callback) => {
_26
// Fetch the already initialized Twilio REST client
_26
const client = context.getTwilioClient();
_26
_26
// Determine message details from the incoming event, with fallback values
_26
const from = event.From || '+15095550100';
_26
const to = event.To || '+15105550101';
_26
const body = event.Body || 'Ahoy, World!';
_26
_26
client.messages
_26
.create({ to, from, body })
_26
.then((result) => {
_26
console.log('Created message using callback');
_26
console.log(result.sid);
_26
// Callback is placed inside the successful response of the request
_26
return callback();
_26
})
_26
.catch((error) => {
_26
console.error(error);
_26
// Callback is also used in the catch handler to end execution on errors
_26
return callback(error);
_26
});
_26
_26
// If you were to place the callback() function here, instead, then the process would
_26
// terminate before your API request to create a message could complete.
_26
};

Return a Simple Successful Response

return-a-simple-successful-response page anchor

Example of how to return an empty HTTP 200 OK


_10
exports.handler = (context, event, callback) => {
_10
// Providing neither error nor response will result in a 200 OK
_10
return callback();
_10
};


Why isn't my code running?

why-isnt-my-code-running page anchor

The most common reason we have seen that a Function appears not to run is the misuse of callback. Your Function invocation terminates when it calls callback. If your request is asynchronous, for example, an API call to a Twilio resource, then you must call callback after the success response of the request has resolved. This would be in the then/catch blocks chained to a request, or after a request that uses the await keyword in an async context.


Can API Calls occur after a Function Execution has ended?

can-api-calls-occur-after-a-function-execution-has-ended page anchor

Yes! Outgoing API requests from inside a Function (either directly via axios/got, or through an SDK such as Twilio's) can still be in an enqueued state even after the execution of a Function has ended.

This happens if you make an asynchronous request that returns a Promise(link takes you to an external page), and forget to either await it or chain on a .then handler. Here, the Function may finish execution before the request occurs or completes. Then, your request may be deferred, sit idle, and run on a subsequent Function invocation in your Service before our system cleans it up.

How do I keep this from happening?

how-do-i-keep-this-from-happening page anchor

Always be sure to wait for the Promises generated by your API calls and methods to resolve before invoking callback. Below are examples of improperly and properly handled asynchronous logic, one which uses .then chaining, and another using async/await syntax.


_10
// An example of an improperly handled Promise
_10
exports.handler = (context, event, callback) => {
_10
const client = context.getTwilioClient();
_10
client.messages.create({
_10
body: "hi",
_10
to: toNumber,
_10
from: fromNumber,
_10
});
_10
return callback(null, 'success');
_10
};


_15
// An example of properly waiting for message creation to
_15
// finish before ending Function execution
_15
exports.handler = (context, event, callback) => {
_15
const client = context.getTwilioClient();
_15
client.messages
_15
.create({
_15
body: 'hi',
_15
to: event.toNumber,
_15
from: event.fromNumber,
_15
})
_15
.then((message) => {
_15
return callback(null, `Success! Message SID: ${message.sid}`);
_15
});
_15
// Ideally, you would also have some .catch logic to handle errors
_15
};


_13
// An example of properly waiting for message creation to
_13
// finish before ending Function execution
_13
exports.handler = async (context, event, callback) => {
_13
const client = context.getTwilioClient();
_13
const message = await client.messages.create({
_13
body: 'hi',
_13
to: event.toNumber,
_13
from: event.fromNumber,
_13
});
_13
_13
return callback(null, `Success! Message SID: ${message.sid}`);
_13
// Ideally, you would add some try/catch logic to handle errors
_13
};


How do I construct Voice TwiML?

how-do-i-construct-voice-twiml page anchor

You can generate Voice TwiML using the Twilio Node library,(link takes you to an external page) which comes packaged within your Function.

Example of how to construct a Voice TwiML Response

Node.js

_10
exports.handler = (context, event, callback) => {
_10
const twiml = new Twilio.twiml.VoiceResponse()
_10
twiml.dial().sip("sip:jack@example.com")
_10
return callback(null, twiml);
_10
}

Output

_10
<?xml version="1.0" encoding="UTF-8"?>
_10
<Response>
_10
<Dial>
_10
<Sip>sip:jack@example.com</Sip>
_10
</Dial
_10
</Response>


How do I construct Messaging TwiML?

how-do-i-construct-messaging-twiml page anchor

You can generate Messaging TwiML using the Twilio Node library(link takes you to an external page), which comes packaged within your Function.

Construct Messaging TwiML

construct-messaging-twiml page anchor

Example of how to construct Messaging TwiML

Node.js

_10
exports.handler = (context, event, callback) => {
_10
const twiml = new Twilio.twiml.MessagingResponse();
_10
twiml.message('The Robots are coming! Head for the hills!');
_10
callback(null, twiml);
_10
}

Output

_10
<?xml version="1.0" encoding="UTF-8"?>
_10
<Response>
_10
<Message>The Robots are coming! Head for the hills!</Message>
_10
</Response>


Simply return your object as outlined in the Function Execution documentation or the following sample code:

Return a Successful JSON Response

return-a-successful-json-response page anchor

Example of how to return JSON in HTTP 200 OK


_10
exports.handler = (context, event, callback) => {
_10
// Construct an object in any way
_10
const response = { result: 'winner winner!' };
_10
// A JavaScript object as a response will be serialized to JSON and returned
_10
// with the Content-Type header set to "application/json" automatically
_10
return callback(null, response);
_10
};


Can I interact with the OPTIONS request?

can-i-interact-with-the-options-request page anchor

No, you cannot interact with the pre-flight OPTIONS request(link takes you to an external page) that browsers send.

The Runtime client will automatically respond to OPTIONS requests with the following values:


_10
Access-Control-Allow-Origin: *
_10
Access-Control-Allow-Headers: *
_10
Access-Control-Allow-Methods: GET, POST, OPTIONS

This means that all origins may access your Function, all headers are passed through, and that the only methods allowed to access your Function are GET, POST, and OPTIONS.


How do I send CORS headers?

how-do-i-send-cors-headers page anchor

You can send CORS headers by using the Twilio Response object described in this example.


How can I use an ES Module in my Function?

how-can-i-use-an-es-module-in-my-function page anchor

If you've tried to use a package such as got or p-retry in your Functions lately, you may have seen this error in your logs:


_15
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/your-name/your-project/node_modules/got/dist/source/index.js
_15
require() of ES modules is not supported.
_15
require() of /Users/your-name/your-project/node_modules/got/dist/source/index.js from /Users/your-name/your-project/functions/retry.js is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
_15
Instead rename index.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /Users/your-name/your-project/node_modules/got/package.json.
_15
_15
at new NodeError (internal/errors.js:322:7)
_15
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1102:13)
_15
at Module.load (internal/modules/cjs/loader.js:950:32)
_15
at Function.Module._load (internal/modules/cjs/loader.js:790:12)
_15
at Module.require (internal/modules/cjs/loader.js:974:19)
_15
at require (internal/modules/cjs/helpers.js:101:18)
_15
at Object. (/Users/your-name/your-project/functions/retry.js:2:13)
_15
at Module._compile (internal/modules/cjs/loader.js:1085:14)
_15
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1114:10)
_15
at Module.load (internal/modules/cjs/loader.js:950:32)

This stems from the fact that packages in the Node.js ecosystem are migrating over from the old CommonJS (CJS) standard to the newer, ES Modules (ESM) standard. You can read about the differences in far more detail in this blog post(link takes you to an external page).

At the moment, Functions only support CJS, but many packages such as p-retry that you might want to use are now only exported as ESM. You could get around this by pinning to an older version of the library that is still CJS, but that opens you up to vulnerabilities and old, unsupported dependencies.

A better solution is to leverage dynamic imports(link takes you to an external page), which allow you to import and run code from an ESM package even if your Function is still in CJS.

Using the import method in this scenario returns a Promise(link takes you to an external page), so you will need to properly handle that promise before running the rest of your Function's code. You can do so by nesting your Function's logic within a .then chain, like so:


_10
exports.handler = (context, event, callback) => {
_10
import('got').then(({ default: got }) => {
_10
got('https://httpbin.org/anything')
_10
.json()
_10
.then((response) => {
_10
// ... the rest of your Function logic
_10
});
_10
});
_10
};

However, it's recommended to leverage async/await syntax(link takes you to an external page) to handle the promise and minimize the amount of chaining/nesting necessary in your Function:


_10
exports.handler = async (context, event, callback) => {
_10
const { default: got } = await import('got');
_10
_10
const response = await got('https://httpbin.org/anything').json();
_10
// ... the rest of your Function logic
_10
};

Note in the above examples that you are destructuring(link takes you to an external page) the default export from the got package, and renaming it to the intended name you'd use when importing it with a static require statement. Refer to this guide on API Calls to see a full example of a Function using dynamic imports with an ESM package.

You can use this same strategy for packages that export multiple, named methods:


_10
const { getPhoneNumbers, ahoy } = await import('some-package');

Lastly, you can import all methods from a package to a single variable, and access them by name like so:


_10
const somePackage = await import('some-package');
_10
_10
somePackage.default(); // Runs the default export from 'some-package'
_10
somePackage.getPhoneNumbers();
_10
somePackage.ahoy('hoy');


Can I execute my Functions on a schedule?

can-i-execute-my-functions-on-a-schedule page anchor

Currently, Functions are event-driven and can only be invoked by HTTP.


Can I see examples of existing Functions?

can-i-see-examples-of-existing-functions page anchor

Absolutely! You can find a variety of examples in the navigation bar as well as on our Function Examples page.


How many Functions can I create?

how-many-functions-can-i-create page anchor

During the Public Beta period, the UI editor can load and present up to 100 Functions or Assets by default. If a service has over 100 Functions or Assets, click on Load more to view the remaining resources, or the next 100 if there are more than that.

The Deploy All and Save buttons, and the ability to change Dependencies, will be disabled until all the Functions and Assets in the service have been loaded. Similarly, it is not possible to delete Functions or Assets until all the Functions or Assets are loaded for view.

To create and manage more Functions and/or Assets, we suggest using the Serverless Toolkit or the Functions and Assets API directly.


What limits are in place on Function invocation?

what-limits-are-in-place-on-function-invocation page anchor

We limit Functions to 30 concurrent invocations — meaning that if you have over 30 Functions being invoked at the same time, you will see new Function invocations return with a 429 status code. To keep below the threshold, optimize your Functions to return as fast as possible — avoid artificial timeouts and use asynchronous calls to external systems rather than waiting on many API calls to complete.


Can I create temporary files when executing a Function?

can-i-create-temporary-files-when-executing-a-function page anchor

Yes. See this blog post(link takes you to an external page) for a description and samples on how to store files for one-off usage.


Are there any Twilio resources for learning Node.js?

are-there-any-twilio-resources-for-learning-nodejs page anchor

Which runtimes are available for Twilio Functions?

which-runtimes-are-available-for-twilio-functions page anchor

The following Node.js runtimes are currently available for Twilio Functions:

runtimeVersionStatusComments
node18Node.js 18.16.1availableDefault for new Services on February 1, 2024
(information)

Info

The runtime value is a parameter that you can provide at build time. See an example on how to pass this parameter, or read the Node.js migration guide for more context.


Rate this page: