Skip to content

Commit d3f7ef4

Browse files
fix(serializer): Required-field validation now respects sub-block visibility (#1313)
1 parent 9a6cc78 commit d3f7ef4

File tree

1 file changed

+66
-6
lines changed

1 file changed

+66
-6
lines changed

apps/sim/serializer/index.ts

Lines changed: 66 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -417,10 +417,6 @@ export class Serializer {
417417
blockConfig: any,
418418
params: Record<string, any>
419419
) {
420-
// Validate user-only required fields before execution starts
421-
// This catches missing API keys, credentials, and other user-provided values early
422-
// Fields that are user-or-llm will be validated later after parameter merging
423-
424420
// Skip validation if the block is in trigger mode
425421
if (block.triggerMode || blockConfig.category === 'triggers') {
426422
logger.info('Skipping validation for block in trigger mode', {
@@ -461,10 +457,74 @@ export class Serializer {
461457
// Iterate through the tool's parameters, not the block's subBlocks
462458
Object.entries(currentTool.params || {}).forEach(([paramId, paramConfig]) => {
463459
if (paramConfig.required && paramConfig.visibility === 'user-only') {
460+
const subBlockConfig = blockConfig.subBlocks?.find((sb: any) => sb.id === paramId)
461+
462+
let shouldValidateParam = true
463+
464+
if (subBlockConfig) {
465+
const isAdvancedMode = block.advancedMode ?? false
466+
const includedByMode = shouldIncludeField(subBlockConfig, isAdvancedMode)
467+
468+
const includedByCondition = (() => {
469+
const evalCond = (
470+
condition:
471+
| {
472+
field: string
473+
value: any
474+
not?: boolean
475+
and?: { field: string; value: any; not?: boolean }
476+
}
477+
| (() => {
478+
field: string
479+
value: any
480+
not?: boolean
481+
and?: { field: string; value: any; not?: boolean }
482+
})
483+
| undefined,
484+
values: Record<string, any>
485+
): boolean => {
486+
if (!condition) return true
487+
const actual = typeof condition === 'function' ? condition() : condition
488+
const fieldValue = values[actual.field]
489+
490+
const valueMatch = Array.isArray(actual.value)
491+
? fieldValue != null &&
492+
(actual.not
493+
? !actual.value.includes(fieldValue)
494+
: actual.value.includes(fieldValue))
495+
: actual.not
496+
? fieldValue !== actual.value
497+
: fieldValue === actual.value
498+
499+
const andMatch = !actual.and
500+
? true
501+
: (() => {
502+
const andFieldValue = values[actual.and!.field]
503+
return Array.isArray(actual.and!.value)
504+
? andFieldValue != null &&
505+
(actual.and!.not
506+
? !actual.and!.value.includes(andFieldValue)
507+
: actual.and!.value.includes(andFieldValue))
508+
: actual.and!.not
509+
? andFieldValue !== actual.and!.value
510+
: andFieldValue === actual.and!.value
511+
})()
512+
513+
return valueMatch && andMatch
514+
}
515+
516+
return evalCond(subBlockConfig.condition, params)
517+
})()
518+
519+
shouldValidateParam = includedByMode && includedByCondition
520+
}
521+
522+
if (!shouldValidateParam) {
523+
return
524+
}
525+
464526
const fieldValue = params[paramId]
465527
if (fieldValue === undefined || fieldValue === null || fieldValue === '') {
466-
// Find the corresponding subBlock to get the display title
467-
const subBlockConfig = blockConfig.subBlocks?.find((sb: any) => sb.id === paramId)
468528
const displayName = subBlockConfig?.title || paramId
469529
missingFields.push(displayName)
470530
}

0 commit comments

Comments
 (0)