diff --git a/docs/generated/postgres-schema/public.instance_monitoring_report.md b/docs/generated/postgres-schema/public.instance_monitoring_report.md
index f2348148da3..038499ca349 100644
--- a/docs/generated/postgres-schema/public.instance_monitoring_report.md
+++ b/docs/generated/postgres-schema/public.instance_monitoring_report.md
@@ -19,7 +19,7 @@
| Name | Type | Definition |
| ---- | ---- | ---------- |
-| CHK_instance_monitoring_report_status | CHECK | CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'delivered'::character varying, 'skipped_after_max_retries'::character varying])::text[]))) |
+| CHK_instance_monitoring_report_status | CHECK | CHECK (((status)::text = ANY ((ARRAY['pending'::character varying, 'delivered'::character varying, 'skipped_after_max_retries'::character varying, 'sending'::character varying])::text[]))) |
| PK_4a5cb8aa51c67e4f5a7eb0f9509 | PRIMARY KEY | PRIMARY KEY (id) |
| instance_monitoring_report_attempts_not_null | n | NOT NULL attempts |
| instance_monitoring_report_createdAt_not_null | n | NOT NULL "createdAt" |
diff --git a/docs/generated/sqlite-schema/instance_monitoring_report.md b/docs/generated/sqlite-schema/instance_monitoring_report.md
index a7d4ab9ba64..6dc0199b126 100644
--- a/docs/generated/sqlite-schema/instance_monitoring_report.md
+++ b/docs/generated/sqlite-schema/instance_monitoring_report.md
@@ -6,7 +6,7 @@
Table Definition
```sql
-CREATE TABLE "instance_monitoring_report" ("id" varchar PRIMARY KEY NOT NULL, "dataPoints" text NOT NULL, "status" varchar(64) NOT NULL DEFAULT ('pending'), "deliveredAt" datetime(3), "attempts" integer NOT NULL DEFAULT (0), "lastAttemptAt" datetime(3), "lastError" text, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "reportDate" varchar(10), CONSTRAINT "CHK_instance_monitoring_report_status" CHECK (("status" IN ('pending', 'delivered', 'skipped_after_max_retries'))))
+CREATE TABLE "instance_monitoring_report" ("id" varchar PRIMARY KEY NOT NULL, "dataPoints" text NOT NULL, "status" varchar(64) NOT NULL DEFAULT ('pending'), "deliveredAt" datetime(3), "attempts" integer NOT NULL DEFAULT (0), "lastAttemptAt" datetime(3), "lastError" text, "createdAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "updatedAt" datetime(3) NOT NULL DEFAULT (STRFTIME('%Y-%m-%d %H:%M:%f', 'NOW')), "reportDate" varchar(10), CONSTRAINT "CHK_instance_monitoring_report_status" CHECK ("status" IN ('pending', 'delivered', 'skipped_after_max_retries', 'sending')))
```
@@ -30,7 +30,7 @@ CREATE TABLE "instance_monitoring_report" ("id" varchar PRIMARY KEY NOT NULL, "d
| Name | Type | Definition |
| ---- | ---- | ---------- |
-| - | CHECK | CHECK (("status" IN ('pending', 'delivered', 'skipped_after_max_retries'))) |
+| - | CHECK | CHECK ("status" IN ('pending', 'delivered', 'skipped_after_max_retries', 'sending')) |
| id | PRIMARY KEY | PRIMARY KEY (id) |
| sqlite_autoindex_instance_monitoring_report_1 | PRIMARY KEY | PRIMARY KEY (id) |
diff --git a/packages/@n8n/db/src/migrations/common/1790774580617-AllowSendingInstanceReportStatus.ts b/packages/@n8n/db/src/migrations/common/1790774580617-AllowSendingInstanceReportStatus.ts
new file mode 100644
index 00000000000..d10e2512b5e
--- /dev/null
+++ b/packages/@n8n/db/src/migrations/common/1790774580617-AllowSendingInstanceReportStatus.ts
@@ -0,0 +1,21 @@
+import type { MigrationContext, ReversibleMigration } from '../migration-types';
+
+const TABLE = 'instance_monitoring_report';
+const COLUMN = 'status';
+const VALUES_BEFORE = ['pending', 'delivered', 'skipped_after_max_retries'];
+const VALUES_AFTER = [...VALUES_BEFORE, 'sending'];
+
+export class AllowSendingInstanceReportStatus1790774580617 implements ReversibleMigration {
+ async up({ schemaBuilder }: MigrationContext) {
+ await schemaBuilder.dropEnumCheck(TABLE, COLUMN, { recreatesOnSqlite: true });
+ await schemaBuilder.addEnumCheck(TABLE, COLUMN, VALUES_AFTER, { recreatesOnSqlite: true });
+ }
+
+ async down({ escape, runQuery, schemaBuilder }: MigrationContext) {
+ await runQuery(
+ `UPDATE ${escape.tableName(TABLE)} SET ${escape.columnName(COLUMN)} = 'pending' WHERE ${escape.columnName(COLUMN)} = 'sending'`,
+ );
+ await schemaBuilder.dropEnumCheck(TABLE, COLUMN, { recreatesOnSqlite: true });
+ await schemaBuilder.addEnumCheck(TABLE, COLUMN, VALUES_BEFORE, { recreatesOnSqlite: true });
+ }
+}
diff --git a/packages/cli/test/migration/1790774580617-allow-sending-instance-report-status.test.ts b/packages/cli/test/migration/1790774580617-allow-sending-instance-report-status.test.ts
new file mode 100644
index 00000000000..afaea021ca8
--- /dev/null
+++ b/packages/cli/test/migration/1790774580617-allow-sending-instance-report-status.test.ts
@@ -0,0 +1,102 @@
+import {
+ createTestMigrationContext,
+ initDbUpToMigration,
+ runSingleMigration,
+ undoLastSingleMigration,
+ type TestMigrationContext,
+} from '@n8n/backend-test-utils';
+import { DbConnection } from '@n8n/db';
+import { Container } from '@n8n/di';
+import { DataSource } from '@n8n/typeorm';
+import { randomUUID } from 'node:crypto';
+
+const MIGRATION_NAME = 'AllowSendingInstanceReportStatus1790774580617';
+const TABLE = 'instance_monitoring_report';
+
+describe('AllowSendingInstanceReportStatus Migration', () => {
+ let dataSource: DataSource;
+
+ beforeAll(async () => {
+ const dbConnection = Container.get(DbConnection);
+ await dbConnection.init();
+ dataSource = Container.get(DataSource);
+ });
+
+ beforeEach(async () => {
+ const context = createTestMigrationContext(dataSource);
+ await context.queryRunner.clearDatabase();
+ await context.queryRunner.release();
+ await initDbUpToMigration(MIGRATION_NAME);
+ });
+
+ afterAll(async () => {
+ const dbConnection = Container.get(DbConnection);
+ await dbConnection.close();
+ });
+
+ async function withContext(run: (context: TestMigrationContext) => Promise): Promise {
+ const context = createTestMigrationContext(dataSource);
+ try {
+ return await run(context);
+ } finally {
+ await context.queryRunner.release();
+ }
+ }
+
+ async function insertReport(context: TestMigrationContext, status: string): Promise {
+ const id = randomUUID();
+ await context.runQuery(
+ `INSERT INTO ${context.escape.tableName(TABLE)}
+ ("id", "dataPoints", "status", "createdAt", "updatedAt")
+ VALUES (:id, '[]', :status, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)`,
+ { id, status },
+ );
+ return id;
+ }
+
+ async function statuses(context: TestMigrationContext): Promise> {
+ const rows = (await context.queryRunner.query(
+ `SELECT "id", "status" FROM ${context.escape.tableName(TABLE)}`,
+ )) as Array<{ id: string; status: string }>;
+ return Object.fromEntries(rows.map((row) => [row.id, row.status]));
+ }
+
+ describe('up', () => {
+ it('accepts a sending report after the migration and still rejects an unknown status', async () => {
+ await withContext(async (context) => {
+ await expect(insertReport(context, 'sending')).rejects.toThrow();
+ });
+
+ await runSingleMigration(MIGRATION_NAME);
+
+ await withContext(async (context) => {
+ await expect(insertReport(context, 'sending')).resolves.toBeDefined();
+ await expect(insertReport(context, 'unknown')).rejects.toThrow();
+ });
+ });
+ });
+
+ describe('down', () => {
+ it('resets sending reports to pending and rejects sending again', async () => {
+ await runSingleMigration(MIGRATION_NAME);
+ const ids = await withContext(async (context) => ({
+ sending: await insertReport(context, 'sending'),
+ pending: await insertReport(context, 'pending'),
+ delivered: await insertReport(context, 'delivered'),
+ skipped: await insertReport(context, 'skipped_after_max_retries'),
+ }));
+
+ await undoLastSingleMigration();
+
+ await withContext(async (context) => {
+ expect(await statuses(context)).toEqual({
+ [ids.sending]: 'pending',
+ [ids.pending]: 'pending',
+ [ids.delivered]: 'delivered',
+ [ids.skipped]: 'skipped_after_max_retries',
+ });
+ await expect(insertReport(context, 'sending')).rejects.toThrow();
+ });
+ });
+ });
+});