Skip to content
Merged
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
46 changes: 46 additions & 0 deletions apps/sim/lib/workflows/credentials/credential-extractor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,49 @@ function formatFieldName(fieldName: string): string {
.join(' ')
}

/**
* Remove malformed subBlocks from a block that may have been created by bugs.
* This includes subBlocks with:
* - Key "undefined" (caused by assigning to undefined key)
* - Missing required `id` field
* - Type "unknown" (indicates malformed data)
*/
function removeMalformedSubBlocks(block: any): void {
if (!block.subBlocks) return

const keysToRemove: string[] = []

Object.entries(block.subBlocks).forEach(([key, subBlock]: [string, any]) => {
// Flag subBlocks with invalid keys (literal "undefined" string)
if (key === 'undefined') {
keysToRemove.push(key)
return
}

// Flag subBlocks that are null or not objects
if (!subBlock || typeof subBlock !== 'object') {
keysToRemove.push(key)
return
}
Comment on lines +184 to +187
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: Arrays pass the typeof !== 'object' check since typeof [] === 'object'. Consider adding !Array.isArray(subBlock) to explicitly reject arrays

Suggested change
if (!subBlock || typeof subBlock !== 'object') {
keysToRemove.push(key)
return
}
// Flag subBlocks that are null or not objects
if (!subBlock || typeof subBlock !== 'object' || Array.isArray(subBlock)) {
keysToRemove.push(key)
return
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/lib/workflows/credentials/credential-extractor.ts
Line: 184:187

Comment:
**style:** Arrays pass the `typeof !== 'object'` check since `typeof [] === 'object'`. Consider adding `!Array.isArray(subBlock)` to explicitly reject arrays

```suggestion
    // Flag subBlocks that are null or not objects
    if (!subBlock || typeof subBlock !== 'object' || Array.isArray(subBlock)) {
      keysToRemove.push(key)
      return
    }
```

How can I resolve this? If you propose a fix, please make it concise.


// Flag subBlocks with type "unknown" (malformed data)
if (subBlock.type === 'unknown') {
keysToRemove.push(key)
return
}

// Flag subBlocks missing required id field
if (!subBlock.id) {
keysToRemove.push(key)
}
})

// Remove the flagged keys
keysToRemove.forEach((key) => {
delete block.subBlocks[key]
})
}

/**
* Sanitize workflow state by removing all credentials and workspace-specific data
* This is used for both template creation and workflow export to ensure consistency
Expand All @@ -183,6 +226,9 @@ export function sanitizeWorkflowForSharing(
Object.values(sanitized.blocks).forEach((block: any) => {
if (!block?.type) return

// First, remove any malformed subBlocks that may have been created by bugs
removeMalformedSubBlocks(block)

const blockConfig = getBlock(block.type)

// Process subBlocks with config
Expand Down
35 changes: 34 additions & 1 deletion apps/sim/stores/workflows/json/importer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,14 @@ import type { WorkflowState } from '../workflow/types'
const logger = createLogger('WorkflowJsonImporter')

/**
* Normalize subblock values by converting empty strings to null.
* Normalize subblock values by converting empty strings to null and filtering out invalid subblocks.
* This provides backwards compatibility for workflows exported before the null sanitization fix,
* preventing Zod validation errors like "Expected array, received string".
*
* Also filters out malformed subBlocks that may have been created by bugs in previous exports:
* - SubBlocks with key "undefined" (caused by assigning to undefined key)
* - SubBlocks missing required fields like `id`
* - SubBlocks with `type: "unknown"` (indicates malformed data)
*/
function normalizeSubblockValues(blocks: Record<string, any>): Record<string, any> {
const normalizedBlocks: Record<string, any> = {}
Expand All @@ -19,6 +24,34 @@ function normalizeSubblockValues(blocks: Record<string, any>): Record<string, an
const normalizedSubBlocks: Record<string, any> = {}

Object.entries(block.subBlocks).forEach(([subBlockId, subBlock]: [string, any]) => {
// Skip subBlocks with invalid keys (literal "undefined" string)
if (subBlockId === 'undefined') {
logger.warn(`Skipping malformed subBlock with key "undefined" in block ${blockId}`)
return
}

// Skip subBlocks that are null or not objects
if (!subBlock || typeof subBlock !== 'object') {
logger.warn(`Skipping invalid subBlock ${subBlockId} in block ${blockId}: not an object`)
return
}
Comment on lines +34 to +37
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: In JavaScript, arrays pass the typeof !== 'object' check since typeof [] === 'object'. Consider adding !Array.isArray(subBlock) to explicitly reject arrays

Suggested change
if (!subBlock || typeof subBlock !== 'object') {
logger.warn(`Skipping invalid subBlock ${subBlockId} in block ${blockId}: not an object`)
return
}
// Skip subBlocks that are null or not objects
if (!subBlock || typeof subBlock !== 'object' || Array.isArray(subBlock)) {
logger.warn(`Skipping invalid subBlock ${subBlockId} in block ${blockId}: not an object`)
return
}
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/sim/stores/workflows/json/importer.ts
Line: 34:37

Comment:
**style:** In JavaScript, arrays pass the `typeof !== 'object'` check since `typeof [] === 'object'`. Consider adding `!Array.isArray(subBlock)` to explicitly reject arrays

```suggestion
        // Skip subBlocks that are null or not objects
        if (!subBlock || typeof subBlock !== 'object' || Array.isArray(subBlock)) {
          logger.warn(`Skipping invalid subBlock ${subBlockId} in block ${blockId}: not an object`)
          return
        }
```

How can I resolve this? If you propose a fix, please make it concise.


// Skip subBlocks with type "unknown" (malformed data)
if (subBlock.type === 'unknown') {
logger.warn(
`Skipping malformed subBlock ${subBlockId} in block ${blockId}: type is "unknown"`
)
return
}

// Skip subBlocks missing required id field
if (!subBlock.id) {
logger.warn(
`Skipping malformed subBlock ${subBlockId} in block ${blockId}: missing id field`
)
return
}

const normalizedSubBlock = { ...subBlock }

// Convert empty strings to null for consistency
Expand Down