What it is
A cold start is not a slow invocation — it is work that happens before any invocation. Lambda creates a container, loads the runtime, imports your module and runs everything at module scope, and only then hands it a request. platform.initStart is written at the beginning of that sequence, which is why it is the one platform record with no request ID: at the moment it is emitted, there is no request.
That has a practical consequence for reading logs. Every other record can be grouped by requestId. This one can only be attributed by position — it belongs to the next invocation to start on that execution environment. On a quiet function that inference is safe. In a log group where several environments are being built at once during a scale-up, several initStart records and several start records interleave, and matching them by eye is guesswork. The reliable cold-start signal in that situation is initDurationMs on the invocation's own platform.report, which needs no inference at all.
initializationType is the field most worth reading, because it answers a question that costs money. on-demand means a real cold start: a user waited for it. provisioned-concurrency means the environment was pre-warmed and the initialisation latency was paid in advance, off the critical path — the record appears at warm-up time rather than at request time. If you are paying for provisioned concurrency and still seeing on-demand in these records during peak traffic, your provisioned capacity is being exceeded and the overflow is falling through to ordinary cold starts. That is exactly the thing provisioned concurrency was bought to prevent, and this field is where it becomes visible.
runtimeVersion deserves an occasional glance too. AWS updates managed runtimes underneath running functions, and a behaviour change with no deployment on your side often correlates with this value moving. It is one of the few places the log records which build actually executed your code.
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
6 raw lines, in the order CloudWatch delivered them.
LogStitch After
The same lines, grouped into the invocation they belong to.
SuccessCold start · 1.23s init0f3a91cc-4f10-4c11-8f0b-1b2d3e4f5a01
- 03:11:04.882PLAT
INIT_START Runtime Version: python:3.12.v41
- 03:11:06.115PLAT
START RequestId: 0f3a91cc-4f10-4c11-8f0b-1b2d3e4f5a01 Version: $LATEST
- 03:11:06.118
Cold container, importing pandas and boto3
- 03:11:06.402
Report generated rows=1204
- 03:11:06.404PLAT
RUNTIME_DONE RequestId: 0f3a91cc-4f10-4c11-8f0b-1b2d3e4f5a01 Status: success Duration: 290.77 ms
- 03:11:06.406PLAT
REPORT RequestId: 0f3a91cc-4f10-4c11-8f0b-1b2d3e4f5a01 Duration: 290.77 ms Billed Duration: 291 ms Memory Size: 1024 MB Max Memory Used: 388 MB Init Duration: 1233.51 ms
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.
| Field | Type | Meaning |
|---|---|---|
| initializationType | string | How the environment was created — on-demand for an ordinary cold start, provisioned-concurrency for a pre-warmed one, snap-start where SnapStart is enabled. This is the field that tells you whether the latency was paid by a user. |
| phase | string | Which initialisation phase this is, normally init. An invoke phase indicates a re-initialisation after the environment failed and was rebuilt during a request. |
| runtimeVersion | string | The exact runtime build, such as nodejs:22.v14. Worth noting when behaviour changes without a deployment — AWS updates these underneath you. |
| runtimeVersionArn | string | The full ARN of that runtime version, which is what you pin against if you need reproducible runtime behaviour. |
When it appears
Only on a cold start — when Lambda creates a new execution environment rather than reusing a warm one. It appears before the platform.start of whichever invocation ends up being served by that environment, and it carries no request ID, because at the moment it is written no request has been assigned yet.
That missing request ID is the awkward part. Every other platform record can be attributed to an invocation by its requestId; this one has to be attributed by position — it belongs to the next platform.start on the same log stream. In a busy log group with several environments starting at once, that attribution is genuinely ambiguous from the text alone.
With provisioned concurrency the record appears when the environment is pre-warmed, which can be minutes or hours before it serves anything, and initializationType reads provisioned-concurrency rather than on-demand.
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.
Related errors
Errors that show up alongside this one, or that people mistake for it.
References
- AWS Lambda Developer Guide — Lambda Telemetry API Event schema reference
- AWS Lambda Developer Guide — Lambda execution environment lifecycle
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.