{"record":{"id":"56794b5ccf5544f3","repo":"heygen-com/hyperframes","slug":"handler-event-has-no-recognised-action-unwrappe","errorCode":null,"errorMessage":"[handler] event has no recognised Action; unwrapped ${MAX_ENVELOPE_DEPTH} levels of Payload/Input without finding one.","messagePattern":"\\[handler\\] event has no recognised Action; unwrapped (.+?) levels of Payload/Input without finding one\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/aws-lambda/src/handler.ts","lineNumber":195,"sourceCode":"  let cursor: LambdaEvent = event;\n  for (let i = 0; i < MAX_ENVELOPE_DEPTH; i++) {\n    if (cursor && typeof cursor === \"object\") {\n      const obj = cursor as Record<string, unknown>;\n      if (typeof obj.Action === \"string\" && isLambdaAction(obj.Action)) {\n        return cursor as PlanEvent | RenderChunkEvent | AssembleEvent;\n      }\n      if (\"Payload\" in obj) {\n        cursor = obj.Payload as LambdaEvent;\n        continue;\n      }\n      if (\"Input\" in obj) {\n        cursor = obj.Input as LambdaEvent;\n        continue;\n      }\n    }\n    break;\n  }\n  throw new Error(\n    `[handler] event has no recognised Action; unwrapped ${MAX_ENVELOPE_DEPTH} levels of Payload/Input without finding one.`,\n  );\n}\n\nfunction isLambdaAction(value: string): value is LambdaAction {\n  return value === \"plan\" || value === \"renderChunk\" || value === \"assemble\";\n}\n\n/**\n * Emit a single JSON line to stdout. CloudWatch ingests each line as a\n * structured event; Logs Insights queries can `filter event=\"...\"` and\n * project specific fields. We write to stdout (not stderr) because\n * Lambda's default destination for both is the same log group, and\n * Logs Insights' INFO/ERROR level parser keys off the JSON `level`\n * field, not the stream.\n */\nfunction logEvent(payload: Record<string, unknown>): void {\n  console.log(JSON.stringify(payload));","sourceCodeStart":177,"sourceCodeEnd":213,"githubUrl":"https://github.com/heygen-com/hyperframes/blob/c2996c8626135db5253519359d8a063d3bafad8d/packages/aws-lambda/src/handler.ts#L177-L213","documentation":"Thrown by `unwrapEvent` after walking up to `MAX_ENVELOPE_DEPTH` (4) levels of Step Functions `Payload`/`Input` envelopes without finding an event whose `Action` is a known `LambdaAction`. The depth cap prevents infinite loops on malformed cyclic input while still tolerating unusual Map/Wait nesting.","triggerScenarios":"An event object whose nested `Payload`/`Input` chain (up to 4 deep) contains no field `Action` with value `plan`/`renderChunk`/`assemble` — e.g. a Step Functions error payload, a misrouted invocation, or an envelope deeper than 4 levels.","commonSituations":"Step Functions map-state iteration passing the raw item instead of `{Action: ...}`; a Catch/Retry path forwarding an error object to the Lambda; refactor that changed the envelope shape past depth 4; CDK/SAM template wiring the wrong input.","solutions":["Inspect the raw Lambda input in CloudWatch to confirm where the `Action` field actually sits.","Fix the Step Functions state definition so the Lambda task input contains `{Action: ..., ...}` within 4 envelope levels.","If a legitimate envelope exceeds depth 4, reconsider the state machine structure rather than bumping the cap.","Verify the producer/orchestrator is emitting the discriminated event, not a wrapper or error object."],"exampleFix":"// before: extra envelope layer pushes Action past depth 4\n{ Payload: { Input: { Payload: { Input: { Payload: { Input: { Action: \"plan\" } } } } } } }\n// after: flatten the state machine so Action lands within 4 levels\n{ Payload: { Input: { Action: \"plan\" } } }","handlingStrategy":"validation","validationCode":"function findAction(event: unknown, maxDepth = 4): string | null {\n  let cursor: unknown = event;\n  for (let i = 0; i < maxDepth && cursor && typeof cursor === \"object\"; i++) {\n    const obj = cursor as Record<string, unknown>;\n    if (typeof obj.Action === \"string\" && /^(plan|renderChunk|assemble)$/.test(obj.Action)) {\n      return obj.Action;\n    }\n    cursor = obj.Payload ?? obj.Input;\n  }\n  return null;\n}\n// assert non-null before invoking the handler","typeGuard":null,"tryCatchPattern":"try {\n  unwrapEvent(event);\n} catch (err) {\n  if (err instanceof Error && /no recognised Action/.test(err.message)) {\n    // log the raw event for diagnosis, surface a typed error to Step Functions\n  }\n  throw err;\n}","preventionTips":["Define Step Functions task inputs so `{Action: ...}` sits within 2 envelope levels (Payload/Input).","Unit-test unwrapEvent against the exact envelope shapes your state machine emits.","Reject misrouted/error payloads at a validation Step before they reach the Lambda."],"tags":["handler","step-functions","envelope","lambda","dispatch"],"backgroundTag":null,"analyzedSha":"c2996c8626135db5253519359d8a063d3bafad8d","analyzedAt":"2026-08-12T22:18:56.877Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}