From d55fb5ec754f9f481cb264c3162a2387f9873839 Mon Sep 17 00:00:00 2001 From: wingding12 <144286538+wingding12@users.noreply.github.com> Date: Sat, 24 Jan 2026 12:35:30 -0500 Subject: [PATCH 1/3] fix: prevent React error #31 when rendering workflow output objects Add safelyRenderValue utility function to handle objects, arrays, and other non-primitive types that could be rendered directly in React components. Applied to: - queued-messages.tsx: msg.content - notifications.tsx: notification.message - todo-list.tsx: todo.content Fixes #2725 --- .../notifications/notifications.tsx | 3 +- .../queued-messages/queued-messages.tsx | 5 ++- .../components/todo-list/todo-list.tsx | 3 +- apps/sim/lib/core/utils/formatting.ts | 39 +++++++++++++++++++ 4 files changed, 47 insertions(+), 3 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx index ddd25134fc..212635c03f 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/notifications/notifications.tsx @@ -3,6 +3,7 @@ import { createLogger } from '@sim/logger' import clsx from 'clsx' import { X } from 'lucide-react' import { Button, Tooltip } from '@/components/emcn' +import { safelyRenderValue } from '@/lib/core/utils/formatting' import { useRegisterGlobalCommands } from '@/app/workspace/[workspaceId]/providers/global-commands-provider' import { createCommands } from '@/app/workspace/[workspaceId]/utils/commands-utils' import { usePreventZoom } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks' @@ -147,7 +148,7 @@ export const Notifications = memo(function Notifications() { {notification.level === 'error' && ( )} - {notification.message} + {safelyRenderValue(notification.message)} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/queued-messages/queued-messages.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/queued-messages/queued-messages.tsx index 15739fcfb3..b4e8e74a1f 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/queued-messages/queued-messages.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/queued-messages/queued-messages.tsx @@ -2,6 +2,7 @@ import { useCallback, useState } from 'react' import { ArrowUp, ChevronDown, ChevronRight, Trash2 } from 'lucide-react' +import { safelyRenderValue } from '@/lib/core/utils/formatting' import { useCopilotStore } from '@/stores/panel/copilot/store' /** @@ -66,7 +67,9 @@ export function QueuedMessages() { {/* Message content */}
-

{msg.content}

+

+ {safelyRenderValue(msg.content)} +

{/* Actions - always visible */} diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx index 8c865f1c21..1b90101913 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/panel/components/copilot/components/todo-list/todo-list.tsx @@ -4,6 +4,7 @@ import { memo, useEffect, useState } from 'react' import { Check, ChevronDown, ChevronRight, Loader2, X } from 'lucide-react' import { Button } from '@/components/emcn' import { cn } from '@/lib/core/utils/cn' +import { safelyRenderValue } from '@/lib/core/utils/formatting' /** * Represents a single todo item @@ -148,7 +149,7 @@ export const TodoList = memo(function TodoList({ : 'text-[var(--text-primary)]' )} > - {todo.content} + {safelyRenderValue(todo.content)}
))} diff --git a/apps/sim/lib/core/utils/formatting.ts b/apps/sim/lib/core/utils/formatting.ts index 3fcf3d6f1b..7af8f9ae0c 100644 --- a/apps/sim/lib/core/utils/formatting.ts +++ b/apps/sim/lib/core/utils/formatting.ts @@ -161,3 +161,42 @@ export function formatDuration(durationMs: number): string { const remainingMinutes = minutes % 60 return `${hours}h ${remainingMinutes}m` } + +/** + * Safely converts a value to a string for React rendering. + * Prevents React error #31 by handling objects, arrays, and other non-primitive types. + * + * @param value - The value to convert to a string + * @returns A string representation safe for React rendering + * + * @example + * safelyRenderValue("hello") // "hello" + * safelyRenderValue(123) // "123" + * safelyRenderValue({ text: "hello", type: "text" }) // '{"text":"hello","type":"text"}' + * safelyRenderValue([1, 2, 3]) // "[1,2,3]" + * safelyRenderValue(null) // "" + * safelyRenderValue(undefined) // "" + */ +export function safelyRenderValue(value: unknown): string { + if (value === null || value === undefined) { + return '' + } + + if (typeof value === 'string') { + return value + } + + if (typeof value === 'number' || typeof value === 'boolean') { + return String(value) + } + + if (typeof value === 'object') { + try { + return JSON.stringify(value) + } catch { + return '[Object]' + } + } + + return String(value) +} From 959374c2081f3bd307c7e22c03cac7b34c29ca36 Mon Sep 17 00:00:00 2001 From: wingding12 <144286538+wingding12@users.noreply.github.com> Date: Sat, 24 Jan 2026 12:50:56 -0500 Subject: [PATCH 2/3] refactor: extract text property from structured objects --- apps/sim/lib/core/utils/formatting.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/sim/lib/core/utils/formatting.ts b/apps/sim/lib/core/utils/formatting.ts index 7af8f9ae0c..9507a1ff73 100644 --- a/apps/sim/lib/core/utils/formatting.ts +++ b/apps/sim/lib/core/utils/formatting.ts @@ -191,6 +191,11 @@ export function safelyRenderValue(value: unknown): string { } if (typeof value === 'object') { + // Handle common structured output pattern {text: string, type?: string} + if ('text' in value && typeof (value as Record).text === 'string') { + return (value as Record).text as string + } + try { return JSON.stringify(value) } catch { From 083fc727f2de1babafb0dac514657a42c7947a23 Mon Sep 17 00:00:00 2001 From: wingding12 <144286538+wingding12@users.noreply.github.com> Date: Sat, 24 Jan 2026 13:00:29 -0500 Subject: [PATCH 3/3] chore: remove redundant comment --- apps/sim/lib/core/utils/formatting.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/sim/lib/core/utils/formatting.ts b/apps/sim/lib/core/utils/formatting.ts index 9507a1ff73..8a54366aa4 100644 --- a/apps/sim/lib/core/utils/formatting.ts +++ b/apps/sim/lib/core/utils/formatting.ts @@ -191,7 +191,6 @@ export function safelyRenderValue(value: unknown): string { } if (typeof value === 'object') { - // Handle common structured output pattern {text: string, type?: string} if ('text' in value && typeof (value as Record).text === 'string') { return (value as Record).text as string }