Zum Inhalt springen
GigadriveDocs

Function errors

Timeouts, memory exhaustion, cold starts and unhandled exceptions in a live Function, and how to tell them apart from a log.

A Function that is already serving fails in four ways that look alike from outside: it ran too long, it ran out of memory, it was not ready, or your code threw. The response status and the runtime log identify which failure occurred.

Timeouts

max_duration bounds one invocation, meaning one HTTP request, one response stream or one WebSocket connection. The default is 30 seconds and the ceiling is 8 hours.

The deadline covers the whole response, including the body, not the time to the first byte. Where it lands decides what the client sees:

  • Nothing sent yet. The invocation is aborted and the edge returns 504 on a branded page carrying the error code EDGE_FUNCTION_TIMEOUT.
  • Headers already sent. The status line is committed and cannot be taken back, so the body stream is cut instead. The client gets a truncated response with a success status and no error page.

Raise max_duration on the Function's config entry when the work genuinely takes that long. When it does not, the runtime log locates the stall: the last line your code logged is the statement before the one that hung.

Memory exhaustion

A Function gets the memory you declared, floored at 256 MB and rounded up to an even number, and one vCPU. That memory belongs to the execution environment and is shared by every request it is serving at that moment, up to 32 at once, so concurrency and memory are not independent settings.

There is no platform error for exceeding it. The kernel kills the process running your code, which produces two symptoms together:

  • Requests in flight fail. The client sees 502. A GET or HEAD is retried once against another environment, and no other method is ever replayed, because the platform cannot know whether your code already committed something.
  • The process is restarted automatically, with a backoff. Requests that arrive during the gap fail the same way, so a Function that dies on start looks like an intermittent 502 rather than a crash.

In the runtime log you either find the interpreter's own message, such as FATAL ERROR: ... JavaScript heap out of memory, arriving on standard error without a request attached, or nothing at all when the kill was immediate.

Raise memory on that Function's entry in gigadrive.yaml. Your plan caps how much you can ask for and the check runs at deploy time, not at request time; Memory and CPU has the numbers.

Cold start symptoms

Publishing a deployment starts nothing. The first request to a Function prepares its image and starts the environment, and a request that cannot be served while that happens is refused rather than queued indefinitely.

StatusError codeWhat it means
503EDGE_FUNCTION_AT_CAPACITYEvery warm environment was busy and another could not be added in time
503EDGE_FUNCTION_RESUMINGThe environment was finishing an idle transition
503EDGE_FUNCTION_STARTINGA sticky-session request whose bound environment is still starting
503EDGE_FUNCTION_START_FAILEDThe start itself failed. Gigadrive is notified
503EDGE_FUNCTION_NOT_READYThe Function's image could not be prepared
503EDGE_ORGANIZATION_COMPUTE_LIMITThe organization is at the active compute its plan includes

The first three carry Retry-After: 2 and clear on their own. The last one needs an administrator: free compute in the console, change plan, or ask support to raise the limit.

A 429 with EDGE_FUNCTION_CONCURRENCY_LIMIT is not a cold start. It means the Function is already processing as many simultaneous requests as the plan allows, covered in Concurrency.

What you can change here is the work your code does before it can answer: everything at module scope runs on every start. Pro and Enterprise plans can also keep an application's production Functions resident, described in The compute model. There are no warmers to configure.

Unhandled exceptions

What an uncaught throw does depends on the shape of your application, and the difference matters because only one of the two shapes survives it.

A handler-style Function, exporting fetch or a request handler, is wrapped by the runtime. A throw is caught and answered with 500 and a JSON body of the form {"errorMessage": "..."}. The process keeps running and the next request is served normally. Nothing is written to your runtime log unless your own code logs it, so a 500 carrying that body with no matching log line is an uncaught throw, not a platform fault.

A server-style Function, an Express, NestJS or raw node:http server, keeps its own error handling and decides its own status. What it does not survive is a throw outside a request or an unhandled promise rejection: Node ends the process, and from there the symptoms are identical to running out of memory, 502 for whatever was in flight followed by a restart.

Catch at the top of your handler and log the error yourself. If you want crashes recorded rather than inferred, add process.on('unhandledRejection') and process.on('uncaughtException') handlers that log before exiting.

Reading a runtime log

Runtime logs live in the console under the environment's Logs page, in one feed with request logs. Filter Activity by Requests or Runtime output, filter Stream by stdout or stderr, pick a time range, and search.

Every line your code writes to standard output or standard error becomes one entry. Calls to console.* made while an invocation is in flight are tagged with that request, which is what fills the Runtime Output panel when you open a request. Anything written outside a request, or written straight to the stream rather than through console, arrives uncorrelated, which is where crash output and startup banners land.

That gives four signatures:

What you seeWhat happened
500 with {"errorMessage": ...}, no log line for itA handler threw and the runtime answered for it
502, and the request's output stops part-wayThe process died mid-request
504, and the last line is where the work stalledThe invocation ran past max_duration
A branded 429 or 503, no runtime output at allYour code never ran. The edge refused the request

To pull the same picture outside the console, list the request logs filtered to server errors. The credential needs the network:requests:read scope.

import { GigadriveClient } from '@gigadrive/sdk';

const client = new GigadriveClient({
  clientId: process.env.GIGADRIVE_CLIENT_ID,
  clientSecret: process.env.GIGADRIVE_CLIENT_SECRET,
});

const { items } = await client.applications.requests.list('0197b2f1-2f4a-7a0b-8a2d-111111111111', {
  statusFamily: 5,
  limit: 100,
});

for (const entry of items) {
  console.log(
    entry.startedAt,
    entry.response.status,
    entry.request.method,
    entry.request.path,
    `${String(entry.metrics.durationMs)}ms`
  );
}

Request logs documents the rest of the filters, and Runtime logs covers the feed itself.