{"record":{"id":"515050cd53e0c524","repo":"mastra-ai/mastra","slug":"experiment-emitted-multiple-terminal-semantic-even","errorCode":null,"errorMessage":"Experiment emitted multiple terminal semantic events","messagePattern":"Experiment emitted multiple terminal semantic events","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/commands/experiment/runtime.ts","lineNumber":581,"sourceCode":"            tenant: packet.tenant,\n            environment: packet.environment,\n            artifacts: packet.artifacts,\n            scorerVersions: Object.fromEntries(packet.scorers.map(scorer => [scorer.id, scorer.version])),\n            policies: packet.policies,\n            requestedAt: packet.requestedAt,\n          },\n          persistence: { experiments: 'none', scores: 'none' },\n          experimentId: request.experimentId,\n          onEvent: async event => {\n            if (event.type === 'experiment.run.started') await writeEvent('run-started', { semanticEvent: event });\n            else if (event.type === 'experiment.item.completed') {\n              await writeEvent('item-completed', {\n                itemId: event.itemId,\n                itemIndex: event.itemIndex,\n                semanticEvent: event,\n              });\n            } else if (event.type === 'experiment.run.finished') {\n              if (finishedEvent) throw new Error('Experiment emitted multiple terminal semantic events');\n              finishedEvent = event;\n            }\n          },\n        }),\n        deadlinePromise,\n      ]);\n    } catch (error) {\n      runErrorRetryable = isRecord(error) && error.retryable === true;\n      runError = error instanceof Error ? error : new Error(String(error));\n    } finally {\n      clearDeadlineTimer?.();\n      clearDeadlineTimer = undefined;\n    }\n    try {\n      let clearTimer: (() => void) | undefined;\n      await Promise.race([\n        mastra.shutdown(),\n        new Promise((_, reject) => {","sourceCodeStart":563,"sourceCodeEnd":599,"githubUrl":"https://github.com/mastra-ai/mastra/blob/75dd419e613fe9c39f846ffc500716141b74fda6/packages/cli/src/commands/experiment/runtime.ts#L563-L599","documentation":"During an experiment run, the CLI processes semantic events from the experiment stream and expects exactly one terminal event ('experiment.run.finished'). This error is thrown when a second terminal event arrives after one has already been recorded, indicating the experiment runtime emitted a malformed or duplicated lifecycle stream.","triggerScenarios":"Calling executeRun with a run whose event stream emits two 'experiment.run.finished' events (e.g. a race between the run completing and the deadline/timeout path also finalizing, or a runtime bug emitting duplicate finish events).","commonSituations":"Running experiments against a runtime that redelivers events, deadlines firing concurrently with normal completion, or a runner that retries and finishes the run twice without a new stream.","solutions":["Inspect the experiment runner for duplicate emission of 'experiment.run.finished' (e.g. both a normal-completion path and a deadline path emitting the event).","Guard the deadline path so it does not emit a terminal event when the run already finished, or abort the stream first.","If events may be redelivered by the transport, make the handler idempotent (ignore or log subsequent terminal events instead of throwing) if duplicate tolerance is acceptable.","Update to the latest @mastra/cli / core versions in case this is a known runtime duplication bug."],"exampleFix":"// before\n} else if (event.type === 'experiment.run.finished') {\n  if (finishedEvent) throw new Error('Experiment emitted multiple terminal semantic events');\n  finishedEvent = event;\n}\n// after\n} else if (event.type === 'experiment.run.finished') {\n  if (finishedEvent) {\n    logger.warn('Ignoring duplicate terminal semantic event');\n    return;\n  }\n  finishedEvent = event;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await executeRun(...);\n} catch (err) {\n  if (err.message === 'Experiment emitted multiple terminal semantic events') {\n    // treat last terminal event as authoritative, or log and re-run with dedup\n  }\n}","preventionTips":["Make terminal-event handling idempotent in custom runners.","Ensure deadline/timeout paths cannot emit after normal completion.","Add stream-level event deduplication before the handler."],"tags":["experiment","runtime","streaming","lifecycle"],"backgroundTag":"duplicate-terminal-event","analyzedSha":"75dd419e613fe9c39f846ffc500716141b74fda6","analyzedAt":"2026-08-30T00:15:31.844Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}