Skip to content

fix(sanitize): repair malformed subblock states#4490

Merged
icecrasher321 merged 3 commits intostagingfrom
fix/legacy-corrupted-states
May 7, 2026
Merged

fix(sanitize): repair malformed subblock states#4490
icecrasher321 merged 3 commits intostagingfrom
fix/legacy-corrupted-states

Conversation

@icecrasher321
Copy link
Copy Markdown
Collaborator

Summary

Repair malformed subblock states from older workflows rather than preventing loading.

Type of Change

  • Bug fix

Testing

Tested manually

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

@vercel
Copy link
Copy Markdown

vercel Bot commented May 7, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped May 7, 2026 7:43am

Request Review

@cursor
Copy link
Copy Markdown

cursor Bot commented May 7, 2026

PR Summary

Medium Risk
Touches workflow load/import and migration/persistence paths; while intended to be backwards-compatible, incorrect sanitization or type inference could still drop/alter legacy subBlock data and affect saved workflows.

Overview
Improves workflow resilience to legacy/malformed subBlocks by repairing or dropping invalid entries instead of failing loads. Adds sanitizeMalformedSubBlocks to normalize metadata (fill missing id/type, coerce type: "unknown" to defaults when configured, convert empty strings to null when requested) and to remove unusable keys like literal "undefined".

Updates migrateSubblockIds to run sanitization for all blocks (not only those with ID renames) and to preserve values when renaming legacy keys (e.g., knowledgeBaseId -> knowledgeBaseSelector) even if the old entry was malformed. Import parsing now unwraps API-style { data: ... } envelopes, extracts workflow names from workflow.name, and runs the same subBlock migration/sanitization during parseWorkflowJson.

Adjusts the migration pipeline ordering so subBlock repairs run before credential ID migration, hardens credential migration against non-object subBlocks, and adds optimistic persistence for migrated blocks by tracking per-block updatedAt and conditioning DB updates on the original timestamp.

Reviewed by Cursor Bugbot for commit b2c6df2. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented May 7, 2026

Greptile Summary

This PR replaces the previous approach of silently dropping malformed subblock entries with a repair-first strategy: a new sanitizeMalformedSubBlocks utility reconstructs missing id/type fields from the block config before falling back to removal, and the ID-rename migration now carries values forward through the repair pass.

  • sanitizeMalformedSubBlocks (new file) handles four cases: literal \"undefined\" keys, non-record values, entries with type: \"unknown\" that match a known config field, and entries with missing metadata — repairing what can be inferred from the block registry and dropping the rest.
  • migrateSubblockIds is extended to run the sanitizer after renaming, and the migration pipeline in utils.ts now runs subblock sanitization before credential-ID rewriting (with a new null-guard in the credential step to handle residual malformed entries).
  • persistMigratedBlocks gains an optimistic-concurrency updatedAt check and now always scopes updates by workflowId, preventing a stale migration from overwriting a user's subsequent save.
  • parseWorkflowJson adds an envelope-unwrapping step so API-wrapped exports (with a data.state shape) parse correctly on import."

Confidence Score: 5/5

Safe to merge — the repair path is well-guarded and the write-back uses optimistic concurrency, so a concurrent user save is never overwritten.

The changes are narrowly scoped to migration and sanitization utilities. The sanitizer's guard ordering is correct, the credential migration gains a defensive null-check, and the optimistic-concurrency lock on write-back prevents data loss. The only finding is a redundant second sanitization pass in the import path, which is a minor efficiency concern with no correctness impact.

No files require special attention; the double-sanitization pass in normalizeSubblockValues inside import-export.ts is the only point worth a follow-up.

Important Files Changed

Filename Overview
apps/sim/lib/workflows/sanitization/subblocks.ts New sanitizer that repairs malformed subBlock metadata and drops unresolvable entries; logic is sound with good guard ordering
apps/sim/lib/workflows/migrations/subblock-migrations.ts Extends the ID-rename migration to also sanitize malformed subBlocks via the new sanitizer; rename logic correctly preserves values and fixes 'unknown' type
apps/sim/lib/workflows/operations/import-export.ts Adds envelope-unwrapping and delegates to migrateSubblockIds+sanitizeMalformedSubBlocks; normalizeSubblockValues runs a redundant second sanitization pass over all blocks
packages/workflow-persistence/src/load.ts Adds blockUpdatedAt tracking and optimistic-concurrency WHERE clause to persistMigratedBlocks; graceful fallback when timestamp not available
apps/sim/lib/workflows/persistence/utils.ts Swaps migration order (subblock sanitization before credential rewrites) and adds a null-guard on subBlock entries before credential ID matching

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[Load workflow blocks from DB] --> B[applyBlockMigrations pipeline]
    B --> C[migrateAgentBlocksToMessagesFormat]
    C --> D[migrateSubblockIds]
    D --> D1{renames for block type?}
    D1 -- yes --> D2[migrateBlockSubblockIds\nrenames IDs, fixes unknown types]
    D1 -- no --> D3[passthrough]
    D2 --> D4[sanitizeMalformedSubBlocks\nrepair or drop bad entries]
    D3 --> D4
    D4 --> E[migrateCredentialIds\nnow guards non-object subBlocks]
    E --> F[backfillCanonicalModes]
    F --> G{any migrated?}
    G -- yes --> H[persistMigratedBlocks\nwith OCC updatedAt guard]
    G -- no --> I[return blocks to caller]
    H --> I

    J[parseWorkflowJson import] --> K[unwrapWorkflowExportEnvelope\nstrips data envelope if present]
    K --> L[normalizeSubblockValues]
    L --> L1[migrateSubblockIds\nincludes sanitizeMalformedSubBlocks]
    L1 --> L2[sanitizeMalformedSubBlocks again\nwith convertEmptyStringToNull]
    L2 --> M[Zod validation]
Loading

Reviews (2): Last reviewed commit: "address comment" | Re-trigger Greptile

Comment thread apps/sim/lib/workflows/sanitization/subblocks.ts Outdated
Comment thread bun.lock
@icecrasher321
Copy link
Copy Markdown
Collaborator Author

bugbot run

@icecrasher321
Copy link
Copy Markdown
Collaborator Author

@greptile

Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit b2c6df2. Configure here.

@icecrasher321 icecrasher321 merged commit 0942555 into staging May 7, 2026
9 of 10 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant