Explorar el Código

fix: wrap validateRuntimeState in try-catch to prevent JSON parse errors from crashing the pipeline

The state validator was throwing an uncaught exception when the LLM output
contains invalid JSON characters (e.g. control chars, unescaped sequences),
causing the entire write pipeline to crash with 'State validator returned
invalid JSON'. This wraps the entire function in a try-catch so that any
such errors are returned as a validation issue rather than crashing.
OpenClaw Bot hace 7 meses
padre
commit
0a1a9064f3
Se han modificado 1 ficheros con 69 adiciones y 59 borrados
  1. 69 59
      packages/core/src/state/state-validator.ts

+ 69 - 59
packages/core/src/state/state-validator.ts

@@ -17,74 +17,84 @@ export function validateRuntimeState(input: {
   readonly hooks: unknown;
   readonly chapterSummaries: unknown;
 }): RuntimeStateValidationIssue[] {
-  const issues: RuntimeStateValidationIssue[] = [];
+  try {
+    const issues: RuntimeStateValidationIssue[] = [];
 
-  const manifest = parseOrIssue(
-    StateManifestSchema,
-    input.manifest,
-    issues,
-    "invalid_manifest",
-    "manifest",
-  );
-  const currentState = parseOrIssue(
-    CurrentStateStateSchema,
-    input.currentState,
-    issues,
-    "invalid_current_state",
-    "currentState",
-  );
-  const hooks = parseOrIssue(
-    HooksStateSchema,
-    input.hooks,
-    issues,
-    "invalid_hooks_state",
-    "hooks",
-  );
-  const chapterSummaries = parseOrIssue(
-    ChapterSummariesStateSchema,
-    input.chapterSummaries,
-    issues,
-    "invalid_chapter_summaries_state",
-    "chapterSummaries",
-  );
+    const manifest = parseOrIssue(
+      StateManifestSchema,
+      input.manifest,
+      issues,
+      "invalid_manifest",
+      "manifest",
+    );
+    const currentState = parseOrIssue(
+      CurrentStateStateSchema,
+      input.currentState,
+      issues,
+      "invalid_current_state",
+      "currentState",
+    );
+    const hooks = parseOrIssue(
+      HooksStateSchema,
+      input.hooks,
+      issues,
+      "invalid_hooks_state",
+      "hooks",
+    );
+    const chapterSummaries = parseOrIssue(
+      ChapterSummariesStateSchema,
+      input.chapterSummaries,
+      issues,
+      "invalid_chapter_summaries_state",
+      "chapterSummaries",
+    );
 
-  if (hooks) {
-    const seen = new Set<string>();
-    for (const hook of hooks.hooks) {
-      if (seen.has(hook.hookId)) {
-        issues.push({
-          code: "duplicate_hook_id",
-          message: `duplicate hook id: ${hook.hookId}`,
-          path: `hooks.${hook.hookId}`,
-        });
+    if (hooks) {
+      const seen = new Set<string>();
+      for (const hook of hooks.hooks) {
+        if (seen.has(hook.hookId)) {
+          issues.push({
+            code: "duplicate_hook_id",
+            message: `duplicate hook id: ${hook.hookId}`,
+            path: `hooks.${hook.hookId}`,
+          });
+        }
+        seen.add(hook.hookId);
       }
-      seen.add(hook.hookId);
     }
-  }
 
-  if (chapterSummaries) {
-    const seen = new Set<number>();
-    for (const row of chapterSummaries.rows) {
-      if (seen.has(row.chapter)) {
-        issues.push({
-          code: "duplicate_summary_chapter",
-          message: `duplicate summary chapter: ${row.chapter}`,
-          path: `chapterSummaries.${row.chapter}`,
-        });
+    if (chapterSummaries) {
+      const seen = new Set<number>();
+      for (const row of chapterSummaries.rows) {
+        if (seen.has(row.chapter)) {
+          issues.push({
+            code: "duplicate_summary_chapter",
+            message: `duplicate summary chapter: ${row.chapter}`,
+            path: `chapterSummaries.${row.chapter}`,
+          });
+        }
+        seen.add(row.chapter);
       }
-      seen.add(row.chapter);
     }
-  }
 
-  if (manifest && currentState && currentState.chapter > manifest.lastAppliedChapter) {
-    issues.push({
-      code: "current_state_ahead_of_manifest",
-      message: `current state chapter ${currentState.chapter} exceeds manifest ${manifest.lastAppliedChapter}`,
-      path: "currentState.chapter",
-    });
-  }
+    if (manifest && currentState && currentState.chapter > manifest.lastAppliedChapter) {
+      issues.push({
+        code: "current_state_ahead_of_manifest",
+        message: `current state chapter ${currentState.chapter} exceeds manifest ${manifest.lastAppliedChapter}`,
+        path: "currentState.chapter",
+      });
+    }
 
-  return issues;
+    return issues;
+  } catch (error) {
+    return [
+      {
+        code: "validator_crash",
+        message: String(error),
+        path: "",
+      },
+    ];
+  }
 }
 
 function parseOrIssue<T>(