Skip to contentSkip to navigationSkip to topbar
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

1
exports.handler = (context, event, callback) => {
2
// Fetch the already initialized Twilio REST client
3
const client = context.getTwilioClient();
4
5
// Determine message details from the incoming event, with fallback values
6
const from = event.From || '+15095550100';
7
const to = event.To || '+15105550101';
8
const body = event.Body || 'Ahoy, World!';
9
10
client.messages
11
.create({ to, from, body })
12
.then((result) => {
13
console.log('Created message using callback');
14
console.log(result.sid);
15
// Callback is placed inside the successful response of the request
16
return callback();
17
})
18
.catch((error) => {
19
console.error(error);
20
// Callback is also used in the catch handler to end execution on errors
21
return callback(error);
22
});
23
24
// If you were to place the callback() function here, instead, then the process would
25
// 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

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

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.

1
// An example of an improperly handled Promise
2
exports.handler = (context, event, callback) => {
3
const client = context.getTwilioClient();
4
client.messages.create({
5
body: "hi",
6
to: toNumber,
7
from: fromNumber,
8
});
9
return callback(null, 'success');
10
};
1
// An example of properly waiting for message creation to
2
// finish before ending Function execution
3
exports.handler = (context, event, callback) => {
4
const client = context.getTwilioClient();
5
client.messages
6
.create({
7
body: 'hi',
8
to: event.toNumber,
9
from: event.fromNumber,
10
})
11
.then((message) => {
12
return callback(null, `Success! Message SID: ${message.sid}`);
13
});
14
// Ideally, you would also have some .catch logic to handle errors
15
};
16
1
// An example of properly waiting for message creation to
2
// finish before ending Function execution
3
exports.handler = async (context, event, callback) => {
4
const client = context.getTwilioClient();
5
const message = await client.messages.create({
6
body: 'hi',
7
to: event.toNumber,
8
from: event.fromNumber,
9
});
10
11
return callback(null, `Success! Message SID: ${message.sid}`);
12
// 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.

Construct Voice TwiMLLink to code sample: Construct Voice TwiML
1
exports.handler = (context, event, callback) => {
2
const twiml = new Twilio.twiml.VoiceResponse()
3
twiml.dial().sip("sip:jack@example.com")
4
return callback(null, twiml);
5
}

Output

1
<?xml version="1.0" encoding="UTF-8"?>
2
<Response>
3
<Dial>
4
<Sip>sip:jack@example.com</Sip>
5
</Dial
6
</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.

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

Output

1
<?xml version="1.0" encoding="UTF-8"?>
2
<Response>
3
<Message>The Robots are coming! Head for the hills!</Message>
4
</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

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

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:

1
Access-Control-Allow-Origin: *
2
Access-Control-Allow-Headers: *
3
Access-Control-Allow-Methods: GET, POST, OPTIONS
4

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:

1
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: /Users/your-name/your-project/node_modules/got/dist/source/index.js
2
require() of ES modules is not supported.
3
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.
4
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.
5
6
at new NodeError (internal/errors.js:322:7)
7
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1102:13)
8
at Module.load (internal/modules/cjs/loader.js:950:32)
9
at Function.Module._load (internal/modules/cjs/loader.js:790:12)
10
at Module.require (internal/modules/cjs/loader.js:974:19)
11
at require (internal/modules/cjs/helpers.js:101:18)
12
at Object. (/Users/your-name/your-project/functions/retry.js:2:13)
13
at Module._compile (internal/modules/cjs/loader.js:1085:14)
14
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:

1
exports.handler = (context, event, callback) => {
2
import('got').then(({ default: got }) => {
3
got('https://httpbin.org/anything')
4
.json()
5
.then((response) => {
6
// ... the rest of your Function logic
7
});
8
});
9
};

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:

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

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:

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:

1
const somePackage = await import('some-package');
2
3
somePackage.default(); // Runs the default export from 'some-package'
4
somePackage.getPhoneNumbers();
5
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.

Need some help?

Terms of service

Copyright © 2024 Twilio Inc.