Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
Null
  • Loading branch information
Sg312 committed Dec 5, 2025
commit 66316d9a7fc67783b908ce5d3cb85a311759e569
42 changes: 5 additions & 37 deletions apps/sim/lib/workflows/credentials/credential-extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,35 +32,6 @@ const WORKSPACE_SPECIFIC_TYPES = new Set([
'mcp-server-selector', // User-specific MCP servers
])

/**
* Get the appropriate "cleared" value for a subblock type.
* Uses null for non-string types to avoid Zod validation errors.
*/
function getClearedValueForType(subBlockType: string): null | '' {
// Types that expect arrays - must use null
const arrayTypes = new Set([
'file-upload',
'table',
'tool-input',
'input-format',
'checkbox-list',
'messages-input',
])

// Types that expect booleans - must use null
const booleanTypes = new Set(['switch', 'checkbox'])

// Types that expect objects - must use null
const objectTypes = new Set(['response-format'])

if (arrayTypes.has(subBlockType) || booleanTypes.has(subBlockType) || objectTypes.has(subBlockType)) {
return null
}

// String/selector types can use empty string
return ''
}

// Field IDs that are workspace-specific
const WORKSPACE_SPECIFIC_FIELDS = new Set([
'knowledgeBaseId',
Expand Down Expand Up @@ -219,11 +190,10 @@ export function sanitizeWorkflowForSharing(
blockConfig.subBlocks?.forEach((subBlockConfig: SubBlockConfig) => {
if (block.subBlocks?.[subBlockConfig.id]) {
const subBlock = block.subBlocks[subBlockConfig.id]
const clearedValue = getClearedValueForType(subBlockConfig.type)

// Clear OAuth credentials (type: 'oauth-input')
if (subBlockConfig.type === 'oauth-input') {
block.subBlocks[subBlockConfig.id].value = clearedValue
block.subBlocks[subBlockConfig.id].value = null
}

// Clear secret fields (password: true)
Expand All @@ -237,18 +207,18 @@ export function sanitizeWorkflowForSharing(
) {
// Keep the env var reference
} else {
block.subBlocks[subBlockConfig.id].value = clearedValue
block.subBlocks[subBlockConfig.id].value = null
}
}

// Clear workspace-specific selectors
else if (WORKSPACE_SPECIFIC_TYPES.has(subBlockConfig.type)) {
block.subBlocks[subBlockConfig.id].value = clearedValue
block.subBlocks[subBlockConfig.id].value = null
}

// Clear workspace-specific fields by ID
else if (WORKSPACE_SPECIFIC_FIELDS.has(subBlockConfig.id)) {
block.subBlocks[subBlockConfig.id].value = clearedValue
block.subBlocks[subBlockConfig.id].value = null
}
}
})
Expand All @@ -259,9 +229,7 @@ export function sanitizeWorkflowForSharing(
Object.entries(block.subBlocks).forEach(([key, subBlock]: [string, any]) => {
// Clear workspace-specific fields by key name
if (WORKSPACE_SPECIFIC_FIELDS.has(key)) {
// Use type-aware clearing if type info is available
const clearedValue = subBlock.type ? getClearedValueForType(subBlock.type) : null
subBlock.value = clearedValue
subBlock.value = null
}
})
}
Expand Down
35 changes: 4 additions & 31 deletions apps/sim/stores/workflows/json/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,6 @@ import type { WorkflowState } from '../workflow/types'

const logger = createLogger('WorkflowJsonImporter')

/**
* Subblock types that should NOT have empty string as a value.
* For these types, empty strings should be normalized to null during import.
* This provides backwards compatibility for workflows exported before type-aware sanitization.
*/
const NON_STRING_SUBBLOCK_TYPES = new Set([
// Array types
'file-upload',
'table',
'tool-input',
'input-format',
'checkbox-list',
'messages-input',
// Boolean types
'switch',
'checkbox',
// Object types
'response-format',
])

/**
* Generate new IDs for all blocks and edges to avoid conflicts
*/
Expand Down Expand Up @@ -126,8 +106,8 @@ function regenerateIds(workflowState: WorkflowState): WorkflowState {
}

/**
* Normalize subblock values by converting empty strings to null for non-string types.
* This provides backwards compatibility for workflows exported before type-aware sanitization,
* Normalize subblock values by converting empty strings to null.
* This provides backwards compatibility for workflows exported before the null sanitization fix,
* preventing Zod validation errors like "Expected array, received string".
*/
function normalizeSubblockValues(
Expand All @@ -144,16 +124,9 @@ function normalizeSubblockValues(
Object.entries(block.subBlocks).forEach(([subBlockId, subBlock]: [string, any]) => {
const normalizedSubBlock = { ...subBlock }

// For non-string types, convert empty string to null
if (
NON_STRING_SUBBLOCK_TYPES.has(subBlock.type) &&
normalizedSubBlock.value === ''
) {
// Convert empty strings to null for consistency
if (normalizedSubBlock.value === '') {
normalizedSubBlock.value = null
logger.info(`Normalized empty string to null for ${subBlock.type} field`, {
blockId,
subBlockId,
})
}

normalizedSubBlocks[subBlockId] = normalizedSubBlock
Expand Down
Loading