Fix: n8n_update_partial_workflow fails with additional properties error (#466)

The n8n Public API uses strict JSON schema validation (additionalProperties: false).
The cleanWorkflowForUpdate() function was sending properties that the API rejects.

Changes:
- Filter out activeVersionId and activeVersion (read-only fields)
- Update settings whitelist to include all 12 properties from n8n OpenAPI spec
- Simplify settings handling (empty {} is now accepted by n8n API)

Source of truth for allowed properties:
- https://github.com/n8n-io/n8n/blob/master/packages/cli/src/public-api/v1/handlers/workflows/spec/schemas/workflow.yml
- https://github.com/n8n-io/n8n/blob/master/packages/cli/src/public-api/v1/handlers/workflows/spec/schemas/workflowSettings.yml

Fixes #466

Conceived by Romuald Członkowski - www.aiadvisors.pl/en

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
thesved
2025-12-04 15:46:29 +02:00
committed by Romuald Członkowski
parent c2dc7c9c51
commit 934124fa7b

View File

@@ -149,6 +149,9 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
triggerCount, triggerCount,
shared, shared,
active, active,
// Remove version-related read-only fields (Issue #466)
activeVersionId,
activeVersion,
// Keep everything else // Keep everything else
...cleanedWorkflow ...cleanedWorkflow
} = workflow as any; } = workflow as any;
@@ -173,18 +176,24 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
// - OpenAPI spec: workflowSettings schema // - OpenAPI spec: workflowSettings schema
// - Tested on n8n.estyl.team (cloud) and localhost (self-hosted) // - Tested on n8n.estyl.team (cloud) and localhost (self-hosted)
// Whitelisted settings properties from n8n OpenAPI spec // Whitelisted settings properties from n8n Public API OpenAPI spec
// Source: https://github.com/n8n-io/n8n/blob/master/packages/cli/src/public-api/v1/handlers/workflows/spec/schemas/workflowSettings.yml
//
// CRITICAL: The n8n Public API uses strict JSON schema validation with
// additionalProperties: false. These 12 properties are accepted:
const safeSettingsProperties = [ const safeSettingsProperties = [
'saveExecutionProgress', 'saveExecutionProgress', // boolean
'saveManualExecutions', 'saveManualExecutions', // boolean
'saveDataErrorExecution', 'saveDataErrorExecution', // string enum: 'all' | 'none'
'saveDataSuccessExecution', 'saveDataSuccessExecution', // string enum: 'all' | 'none'
'executionTimeout', 'executionTimeout', // number (max: 3600)
'errorWorkflow', 'errorWorkflow', // string (workflow ID)
'timezone', 'timezone', // string (e.g., 'America/New_York')
'executionOrder', 'executionOrder', // string (e.g., 'v1')
'callerPolicy', 'callerPolicy', // string enum: 'any' | 'none' | 'workflowsFromAList' | 'workflowsFromSameOwner'
'availableInMCP', 'callerIds', // string (comma-separated workflow IDs)
'timeSavedPerExecution', // number (in minutes)
'availableInMCP', // boolean (default: false)
]; ];
if (cleanedWorkflow.settings && typeof cleanedWorkflow.settings === 'object') { if (cleanedWorkflow.settings && typeof cleanedWorkflow.settings === 'object') {
@@ -196,18 +205,14 @@ export function cleanWorkflowForUpdate(workflow: Workflow): Partial<Workflow> {
} }
} }
// n8n API requires settings to be present but rejects empty settings objects. // n8n API behavior with settings:
// If no valid properties remain after filtering, include minimal default settings. // - The settings property is REQUIRED by the API
if (Object.keys(filteredSettings).length > 0) { // - Empty settings objects {} are now accepted (n8n preserves existing settings)
// - Only whitelisted properties are accepted; others cause "additional properties" error
cleanedWorkflow.settings = filteredSettings; cleanedWorkflow.settings = filteredSettings;
} else { } else {
// Provide minimal valid settings (executionOrder v1 is the modern default) // No settings provided - use empty object (required by API)
cleanedWorkflow.settings = { executionOrder: 'v1' as const }; cleanedWorkflow.settings = {};
}
} else {
// No settings provided - include minimal default settings
// n8n API requires settings in workflow updates (v1 is the modern default)
cleanedWorkflow.settings = { executionOrder: 'v1' as const };
} }
return cleanedWorkflow; return cleanedWorkflow;