{"record":{"id":"cd1133fc98c306cc","repo":"n8n-io/n8n","slug":"admittance-rejected","errorCode":"admittance_rejected","errorMessage":"Execution admittance rejected: ${reason}","messagePattern":"Execution admittance rejected: (.+?)","errorType":"http","errorClass":"AdmittanceRejectedError","httpStatus":429,"severity":"warning","filePath":"packages/@n8n/engine/src/execution/start-execution.service.ts","lineNumber":34,"sourceCode":"\texecutionId: string;\n}\n\nexport class StartExecutionService {\n\tconstructor(\n\t\tprivate readonly admittance: AdmittanceService,\n\t\tprivate readonly executionStore: ExecutionStore,\n\t\tprivate readonly workQueue: WorkQueue<OrchestrationMessage>,\n\t\tprivate readonly validateGraph: (graph: WorkflowGraph) => void = validateExecutableGraph,\n\t) {}\n\n\tasync start(request: StartExecutionRequest): Promise<StartExecutionResult> {\n\t\t// Rejected before admittance: a graph that can never run shouldn't spend\n\t\t// admittance capacity, and nothing is persisted for it.\n\t\tthis.validateGraph(request.graph);\n\n\t\tconst decision = await this.admittance.evaluate({ workflowId: request.workflowId });\n\t\tif (!decision.accept) {\n\t\t\tthrow new AdmittanceRejectedError(decision.reason);\n\t\t}\n\n\t\tconst { id } = await this.executionStore.createExecution({\n\t\t\tworkflowId: request.workflowId,\n\t\t\t// admitted; a worker flips this to 'running' when it starts\n\t\t\tstatus: 'queued',\n\t\t\tmode: request.mode ?? 'production',\n\t\t\tgraph: request.graph,\n\t\t\ttriggerPayload: request.triggerPayload ?? null,\n\t\t});\n\n\t\t// TODO(CAT-2938): the persist above and this publish aren't atomic — a\n\t\t// crash between them leaves the execution 'queued' until the\n\t\t// reconciliation sweep (not yet built) re-dispatches it.\n\t\tawait this.workQueue.publish({\n\t\t\ttype: 'execution:enqueued',\n\t\t\texecutionId: id,\n\t\t});","sourceCodeStart":16,"sourceCodeEnd":52,"githubUrl":"https://github.com/n8n-io/n8n/blob/5ac6606e81f67bb9534255570cd4e86fd8101eee/packages/@n8n/engine/src/execution/start-execution.service.ts#L16-L52","documentation":"AdmittanceRejectedError (code: admittance_rejected) thrown by StartExecutionService.start() after graph validation passes but the admittance service (this.admittance.evaluate) returns a decision with accept === false. The decision.reason is interpolated into the message. Notably, nothing is persisted for rejected executions — they fail before executionStore.createExecution is called, so no execution record exists.","triggerScenarios":"Calling start() for a workflow when admittance denies it — e.g. concurrent-execution limits reached, per-workflow rate limits, quota exhaustion, a global 'executions paused' state, or resource-based back-pressure. The admittance service's policy determines the reason.","commonSituations":"A trigger firing while the workflow is already at its max-concurrent-executions; an org over plan quota; maintenance mode; a worker pool saturated so admittance conservatively rejects; misconfigured admittance policy that is too strict.","solutions":["Inspect decision.reason — it tells you which limit/policy fired; address that specifically (raise concurrency, clear quota, exit maintenance).","If concurrent-execution limit is hit, await an in-flight execution or raise the configured cap.","For rate/quota rejections, back off and retry with jitter, or upgrade the plan / adjust the policy.","If maintenance mode is on, exit it before submitting executions.","Since nothing is persisted on rejection, instrument caller-side metrics to track rejection reasons."],"exampleFix":"// before\nconst result = await startExecution.start(request);\n\n// after\nconst decision = await admittance.evaluate({ workflowId: request.workflowId });\nif (!decision.accept) {\n  // schedule a retry with backoff, or surface to the user\n  throw new UserError(`Execution not admitted: ${decision.reason}`);\n}\nconst result = await startExecution.start(request);","handlingStrategy":"try-catch","validationCode":"const decision = await admittance.evaluate({ workflowId: request.workflowId });\nif (!decision.accept) {\n  // do not call start; schedule a retry with backoff or surface to user\n}","typeGuard":"function isAdmittanceRejected(err: unknown): boolean {\n  return err instanceof AdmittanceRejectedError || (err instanceof Error && /^Execution admittance rejected:/.test(err.message));\n}","tryCatchPattern":"try {\n  await start(request);\n} catch (err) {\n  if (isAdmittanceRejected(err)) {\n    // inspect decision.reason; back off, queue, or fail open per policy\n  } else throw err;\n}","preventionTips":["Pre-evaluate admittance before doing expensive graph prep.","Track rejection reasons in metrics — nothing is persisted on rejection.","Tune admittance policy (concurrency, quotas) to match real workload."],"tags":["execution","admittance","rate-limit","quota","engine"],"backgroundTag":null,"analyzedSha":"5ac6606e81f67bb9534255570cd4e86fd8101eee","analyzedAt":"2026-08-12T05:26:35.080Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}