Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

35 changes: 12 additions & 23 deletions src/services/n8n-validation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,29 +129,18 @@ export function cleanWorkflowForCreate(workflow: Partial<Workflow>): Partial<Wor
* @returns A cleaned partial workflow suitable for API updates
*/
export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
const {
// Remove read-only/computed fields
id,
createdAt,
updatedAt,
versionId,
versionCounter, // Added: n8n 1.118.1+ returns this but rejects it in updates
meta,
staticData,
// Remove fields that cause API errors
pinData,
tags,
description, // Issue #431: n8n returns this field but rejects it in updates
// Remove additional fields that n8n API doesn't accept
isArchived,
usedCredentials,
sharedWithProjects,
triggerCount,
shared,
active,
// Keep everything else
...cleanedWorkflow
} = workflow as any;
// Use whitelist approach: only include properties that n8n API accepts
// This prevents "additional properties" errors from cloud-specific fields
// like ownedBy, homeProject, sharedWith, display, usageCount, parentFolderId, etc.
const cleanedWorkflow: Partial<Workflow> = {};

// Only include properties that n8n API accepts in PUT /workflows/{id}
const whitelistedProperties = ['name', 'nodes', 'connections', 'settings', 'active', 'tags'] as const;
for (const key of whitelistedProperties) {
if (key in workflow) {
(cleanedWorkflow as any)[key] = (workflow as any)[key];
}
}
Comment on lines +138 to +143

// CRITICAL FIX for Issue #248:
// The n8n API has version-specific behavior for settings in workflow updates:
Expand Down
16 changes: 8 additions & 8 deletions tests/unit/services/n8n-validation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -329,24 +329,23 @@ describe('n8n-validation', () => {

const cleaned = cleanWorkflowForUpdate(workflow);

// Should remove all these fields
// With whitelist approach, only name, nodes, connections, settings, active, tags are kept
expect(cleaned).not.toHaveProperty('id');
Comment on lines 330 to 333
expect(cleaned).not.toHaveProperty('createdAt');
expect(cleaned).not.toHaveProperty('updatedAt');
expect(cleaned).not.toHaveProperty('versionId');
expect(cleaned).not.toHaveProperty('versionCounter'); // n8n 1.118.1+ compatibility
expect(cleaned).not.toHaveProperty('versionCounter');
expect(cleaned).not.toHaveProperty('meta');
expect(cleaned).not.toHaveProperty('staticData');
expect(cleaned).not.toHaveProperty('pinData');
expect(cleaned).not.toHaveProperty('tags');
expect(cleaned).not.toHaveProperty('isArchived');
expect(cleaned).not.toHaveProperty('usedCredentials');
expect(cleaned).not.toHaveProperty('sharedWithProjects');
expect(cleaned).not.toHaveProperty('triggerCount');
expect(cleaned).not.toHaveProperty('shared');
expect(cleaned).not.toHaveProperty('active');

// Should keep name and filter settings to safe properties
// active and tags ARE whitelisted, so they should be present
expect(cleaned).toHaveProperty('active');
expect(cleaned).toHaveProperty('tags'); // Should keep name and filter settings to safe properties
expect(cleaned.name).toBe('Updated Workflow');
Comment on lines +346 to 349
expect(cleaned.settings).toEqual({ executionOrder: 'v1' });
});
Expand Down Expand Up @@ -1405,8 +1404,9 @@ describe('n8n-validation', () => {
expect(forUpdate).not.toHaveProperty('createdAt');
expect(forUpdate).not.toHaveProperty('updatedAt');
expect(forUpdate).not.toHaveProperty('versionId');
expect(forUpdate).not.toHaveProperty('active');
expect(forUpdate).not.toHaveProperty('tags');
// active and tags ARE whitelisted, so they should be present
expect(forUpdate).toHaveProperty('active');
expect(forUpdate).toHaveProperty('tags');
expect(forUpdate).not.toHaveProperty('meta');
// n8n API requires settings in updates, so minimal defaults (v1) are provided (Issue #431)
expect(forUpdate.settings).toEqual({ executionOrder: 'v1' });
Expand Down