platform.runtimeDone

Short answer

platform.runtimeDone marks the moment the runtime handed the response back, before billing is finalised. It has no equivalent in the text log format — it exists only in JSON logging, and its status field is the runtime's own verdict on whether the invocation worked.

What it is

Of the four platform records that bracket an invocation, this is the only one with nothing corresponding to it in the text log format. Text logging gives you START, END and REPORT. JSON logging gives you platform.start, platform.runtimeDone and platform.report — and runtimeDone carries information the text format simply never had.

The valuable part is status. It is the runtime's own report of how the invocation ended, written by the platform rather than derived from anything your code printed. Determining whether an invocation failed from text logs means scanning for exception patterns, stack traces, or the phrase "Task timed out" — heuristics that work well until a message is truncated, a stack trace is interleaved with another execution's output, or the function fails without logging anything at all. This field is none of those things. It is an assertion.

producedBytes is the quieter field and worth watching. It measures the response your handler returned, and Lambda caps a synchronous response at 6 MB. An endpoint whose response grows with the data behind it — a list with no pagination, an export that gets larger every month — will cross that limit eventually, and this field is where the approach is visible beforehand. Watching it climb across invocations is considerably cheaper than discovering the ceiling when your largest customer does.

There is one diagnostic worth knowing that comes from this record being absent. It is emitted when the runtime finishes normally. A process killed by the out-of-memory killer never gets there — the kernel removes it between instructions — so the invocation produces a platform.report with no platform.runtimeDone before it. That asymmetry is one of the clearest available signals that a function was killed rather than that it failed, and it is only visible if you are looking at the records of one invocation together rather than scrolling a merged stream.

What it looks like in your logs

With Advanced Logging Controls set to JSON, this record arrives as an envelope. Here it is raw, and then read the way the text format would have shown it.

CloudWatch Logs Before

5 raw lines, in the order CloudWatch delivered them.

{"time":"2026-09-01T11:22:44.102Z","type":"platform.start","record":{"requestId":"c39e5a72-1d64-4f80-a123-7e4c9b1d5f62","version":"$LATEST"}}
{"time":"2026-09-01T11:22:44.108Z","type":"function","record":"Building monthly export"}
{"time":"2026-09-01T11:22:45.902Z","type":"function","record":"Assembled 18402 rows"}
{"time":"2026-09-01T11:22:45.944Z","type":"platform.runtimeDone","record":{"requestId":"c39e5a72-1d64-4f80-a123-7e4c9b1d5f62","status":"success","metrics":{"durationMs":1842.07,"producedBytes":4718592}}}
{"time":"2026-09-01T11:22:45.948Z","type":"platform.report","record":{"requestId":"c39e5a72-1d64-4f80-a123-7e4c9b1d5f62","status":"success","metrics":{"durationMs":1842.07,"billedDurationMs":1843,"memorySizeMB":1024,"maxMemoryUsedMB":412}}}

LogStitch After

The same lines, grouped into the invocation they belong to.

Successc39e5a72-1d64-4f80-a123-7e4c9b1d5f62dur 1.84sbilled 1.84smem 412/1024MBlogs 5
  1. 11:22:44.102PLAT
    START RequestId: c39e5a72-1d64-4f80-a123-7e4c9b1d5f62 Version: $LATEST
  2. 11:22:44.108
    Building monthly export
  3. 11:22:45.902
    Assembled 18402 rows
  4. 11:22:45.944PLAT
    RUNTIME_DONE RequestId: c39e5a72-1d64-4f80-a123-7e4c9b1d5f62	Status: success	Duration: 1842.07 ms
  5. 11:22:45.948PLAT
    REPORT RequestId: c39e5a72-1d64-4f80-a123-7e4c9b1d5f62	Duration: 1842.07 ms	Billed Duration: 1843 ms	Memory Size: 1024 MB	Max Memory Used: 412 MB
Success
Status
1.84s
Duration
1.84s
Billed
412/1024MB
Memory
60%
Headroom
No
Cold start

The panel on the right is generated by running the excerpt on the left through the same parser that powers the free web stitcher — it is what the tool actually produces for this input, not an illustration of it.

What the record contains

Every field Lambda writes in this record, and what each one is telling you.

FieldTypeMeaning
requestId string The invocation this completion belongs to, matching its platform.start.
status string The runtime's verdict — success, failure, or timeout. This is written by the platform rather than inferred from log text, which makes it the most authoritative status signal in the log.
metrics.durationMs number How long the runtime spent on the invocation. Compare it against the duration on platform.report to see what accounting added.
metrics.producedBytes number The size of the response the handler returned. Useful for spotting a payload creeping toward Lambda's 6 MB response limit before it crosses it.

When it appears

Once per invocation, between the function's last output and its platform.report. It is emitted when the runtime finishes with the request — after your handler returns or throws, and before Lambda has finished accounting for the execution.

Its position is what makes it useful. The gap between platform.runtimeDone and platform.report is post-processing the runtime does after your code is finished, so a response that takes a long time to serialise or a large payload to transmit shows up as separation between these two timestamps rather than in your handler's own duration.

It is also the record most often missing when something is genuinely wrong. An invocation killed by the out-of-memory killer never reaches it, because the process no longer exists — so a request ID with a platform.report and no platform.runtimeDone is a strong signal that the runtime died rather than returned.

Also seen as

The same underlying failure, worded differently by a different runtime, SDK version, or logging layer. All of these land here — there is no separate page for each phrasing.

"type":"platform.runtimeDone"platform.runtimeDone recordRUNTIME_DONE lambdalambda runtimeDone status failureproducedBytes lambda

Errors that show up alongside this one, or that people mistake for it.

References

Stop reading JSON envelopes.

LogStitch renders every one of these records as a single readable line, in the invocation it belongs to — the same way the text format shows them, with the raw envelope one toggle away. Paste a log excerpt into the free web stitcher and see it, or run the Mac app against your own AWS profiles.