Integration item parked
Fires when a failed Lattice integration item is parked in the integration dead-letter queue for manual review, the terminal state an operator has to act on. Items reach the queue when a Lattice asynchronous operation or a file ingestion segment fails; a non-retryable failure is parked straight away, and a retryable one is parked once the dead-letter retry sweep has used up its attempts. The Lattice dead-letter retry background process runs that sweep every 5 minutes, so there is nothing to schedule, but retryable failures raise this event only while it (or a scheduled sweep in its place) runs. Monitoring tools such as Power Automate or a Logic App can subscribe to raise an incident or notify the integration team. The payload carries only non-sensitive identification and diagnostic fields: never the original request payload, the original request ID, the source reference, or any credential.
| Event class | MGCLatticeIntegrationFailureBusinessEvent |
| Contract class | MGCLatticeIntegrationFailureBusinessEventContract |
| Category | System administration |
| Module | ModuleAxapta::SystemAdministration |
| Label IDs | IntegrationFailureBusinessEventName / IntegrationFailureBusinessEventDesc |
| Trigger | MGCLatticeIntegrationDlqAlert.onParked() -> a dead-letter row has just moved to Parked (at enqueue, or when the retry sweep exhausts its attempts) |
Trigger / Hook
- Send site:
MGCLatticeIntegrationDlqAlert.raiseBusinessEvent(), called fromonParked()(via the staticonParkedStatic()).onParked()returns without doing anything when the dead-letter record is empty. This business event is the only alert Lattice raises when an item is parked: Lattice sends no email of its own. To have someone emailed, subscribe a Power Automate flow or a Logic App to this event. - It's called from the two places that park a dead-letter row and alert, each time after that row's transaction has committed:
MGCLatticeIntegrationDlqManager::enqueue(): when a failure is enqueued as non-retryable it's inserted directly with statusParked. File ingestion segment failures are always enqueued this way; asynchronous operation failures are when the operation reports them as non-retryable. Enqueue is idempotent per source reference, so a failure that's already queued doesn't park, or alert, again.MGCLatticeIntegrationDlqRetryBatch.run(): the dead-letter retry sweep, which the Lattice dead-letter retry background process runs every 5 minutes when a row is due, replays everyRetryingrow that is due. When a replay fails and the row'sAttemptCountreachesMaxAttempts(5 by default), the row is set toParkedand the event is raised. Until then the row is rescheduled with an exponential backoff (60 seconds, doubling per attempt, capped at one hour).
- Dependency: retryable failures only reach
Parkedthrough the retry sweep, and so only then raise this event. If the Lattice dead-letter retry background process is switched off and no sweep is scheduled in its place, they stay inRetryingand never raise it. - Not raised: a manual fix and resubmit from the integration operations console (
MGCLatticeIntegrationDlqManager.resubmit()) that fails also sets the row toParked, but doesn't raise the event; the operator who resubmitted sees the result on screen. - Enablement gate:
BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeIntegrationFailureBusinessEvent)), checked inraiseBusinessEvent()before the event is built, so while the event is not activated, parking an item raises no alert at all. Any exception while raising the event is caught and reported in the infolog so the parking isn't affected; the catch does run, because both callers invoke the alert after their transaction has committed.
protected void raiseBusinessEvent(MGCLatticeIntegrationDeadLetter _deadLetter)
{
try
{
if (BusinessEventsConfigurationReader::isBusinessEventEnabled(classStr(MGCLatticeIntegrationFailureBusinessEvent)))
{
MGCLatticeIntegrationFailureBusinessEvent::newFromDeadLetter(_deadLetter).send();
}
}
catch
{
// Alerting is best-effort and must never break the park path.
error(strFmt("@MGCLattice:DlqAlertBusinessEventFailed", MGCLatticeGuidFormat::toText(_deadLetter.DeadLetterId)));
}
}
Payload Contract
One row per [DataMember], in declaration order. Sources are the parked MGCLatticeIntegrationDeadLetter row, mapped in initialize(). Each enum is sent as its integer value plus its symbol in a ...Name member.
| JSON field | Display label | Type / EDT | Source | Notes |
|---|---|---|---|---|
deadLetterId | Dead-letter ID | str | MGCLatticeIntegrationDeadLetter.DeadLetterId | Identifier of the dead-letter row, assigned at enqueue |
sourceType | Source type | int | MGCLatticeIntegrationDeadLetter.SourceType | MGCLatticeIntegrationDlqSource: 1 = AsyncOperation, 2 = FileIngestion |
sourceTypeName | Source type name | str | SourceType (enum symbol) | "AsyncOperation" or "FileIngestion" |
serviceName | Service | str | MGCLatticeIntegrationDeadLetter.ServiceName | Target service of the failed item; for file ingestion, the connection ID (empty when the connection couldn't be resolved) |
operationName | Operation | str | MGCLatticeIntegrationDeadLetter.OperationName | Target operation; "processOneSegment" for file ingestion |
errorCode | Error code | int | MGCLatticeIntegrationDeadLetter.ErrorCode | MGCLatticeServiceErrorCode value, for example 1 = ValidationFailed, 4 = BusinessRule, 6 = TransientRuntime, 11 = ConfigurationMissing |
errorCodeName | Error code name | str | ErrorCode (enum symbol) | For example "BusinessRule", "ValidationFailed", "TransientRuntime", "ConfigurationMissing" |
status | Status | int | MGCLatticeIntegrationDeadLetter.Status | MGCLatticeIntegrationDlqStatus; always 2 (Parked) when this event is raised |
statusName | Status name | str | Status (enum symbol) | Always "Parked" when this event is raised |
attemptCount | Attempts | int | MGCLatticeIntegrationDeadLetter.AttemptCount | 0 when parked at enqueue; equals the row's MaxAttempts when parked by the retry sweep |
firstFailedDateTime | First failed | utcdatetime | MGCLatticeIntegrationDeadLetter.FirstFailedDateTimeUtc | When the item was first dead-lettered (UTC); \/Date(ms)\/ form |
failureMessage | Failure message | str | MGCLatticeIntegrationDeadLetter.FailureMessage | Cut to the first 512 characters |
Every Lattice event also carries the Lattice ordering and correlation envelope, inherited from MGCLatticeBusinessEventContractBase: eventSequence (Int64 - increasing across the whole catalog and all companies, allocated when the event is raised; it orders the events of one record, gaps are normal and permanent, see the README), correlationId (String - always Scope:Key; groups emissions that belong to one logical run and defaults to Event: plus a GUID unique to this emission) and schemaVersion (Int - the payload shape version; 1 for this contract). D365 F&O also adds its standard envelope fields to every business event payload: BusinessEventId, BusinessEventLegalEntity, ContextRecordSubject, ControlNumber, EventId, EventTime, EventTimeIso8601, InitiatingUserAADObjectId, MajorVersion, MinorVersion, and ParentContextRecordSubjects. Do not rely on the order of members in the delivered JSON.
This event doesn't call correlateTo, so correlationId is unique to each emission; use deadLetterId to find the item in the integration operations console.
Example Payload
An asynchronous journal-posting operation that failed and was parked after five retries:
{
"BusinessEventId": "MGCLatticeIntegrationFailureBusinessEvent",
"ControlNumber": 5637150870,
"EventId": "2F6B9D04-E3A7-4C15-8B92-5A0D7E1C6F38",
"EventTime": "\/Date(1790250250000)\/",
"EventTimeIso8601": "2026-09-24T11:44:10.7462213Z",
"MajorVersion": 0,
"MinorVersion": 0,
"BusinessEventLegalEntity": "USMF",
"ContextRecordSubject": "",
"InitiatingUserAADObjectId": "{66AFCCC8-F547-8DAB-C783-430AD85BEA0D}",
"ParentContextRecordSubjects": [],
"eventSequence": 48344,
"correlationId": "Event:9c1e5a27-40b8-4f63-a2d9-e6b03f7c1d84",
"schemaVersion": 1,
"deadLetterId": "5d8a2c71-3e4f-4b90-a6c2-1f7e9b0d3a65",
"sourceType": 1,
"sourceTypeName": "AsyncOperation",
"serviceName": "MGCLatticeGeneralLedgerJournalService",
"operationName": "postGeneralJournal",
"errorCode": 6,
"errorCodeName": "TransientRuntime",
"status": 2,
"statusName": "Parked",
"attemptCount": 5,
"firstFailedDateTime": "\/Date(1790241242000)\/",
"failureMessage": "The operation failed due to an integration runtime error."
}
Activation
In the D365FO client, go to System administration > Setup > Business events > Business events catalog. Find this event by name ("Integration item parked") or by filtering the Category column to System administration. Select it and use Activate to bind it to a configured endpoint (for example, an Azure Service Bus queue, Event Grid topic, or HTTPS webhook).
There is nothing to schedule: retryable failures park, and raise the event, through the Lattice dead-letter retry background process, which looks for due items every 5 minutes. Keep it enabled on System administration > Setup > Process automations > Background processes. System administration > Periodic tasks > Lattice > Run integration dead-letter retry sweep (menu item MGCLatticeIntegrationDlqRetry) runs the sweep once, now. Parked items are reviewed, replayed, or discarded in System administration > Inquiries > Lattice > Integration operations > Integration operations console.