{"record":{"id":"caf8ed9a14c00b8b","repo":"windmill-labs/windmill","slug":"invalid-json-for-field-errormessage","errorCode":null,"errorMessage":"Invalid JSON for ${field}: ${errorMessage}","messagePattern":"Invalid JSON for (.+?): (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"frontend/src/lib/components/copilot/chat/flow/core.ts","lineNumber":250,"sourceCode":")\n\nconst specialFlowModuleFields = {\n\tpreprocessor_module: SPECIAL_MODULE_IDS.PREPROCESSOR,\n\tfailure_module: SPECIAL_MODULE_IDS.FAILURE\n} as const\n\ntype SpecialFlowModuleField = keyof typeof specialFlowModuleFields\n\nfunction parseOptionalJsonArg(value: unknown, field: string): unknown {\n\tif (value === undefined || value === null) {\n\t\treturn value\n\t}\n\n\ttry {\n\t\treturn typeof value === 'string' ? JSON.parse(value) : value\n\t} catch (e) {\n\t\tconst errorMessage = e instanceof Error ? e.message : String(e)\n\t\tthrow new Error(`Invalid JSON for ${field}: ${errorMessage}`)\n\t}\n}\n\nfunction validateSpecialFlowModule(\n\tmodule: unknown,\n\tfield: SpecialFlowModuleField\n): FlowModule | null | undefined {\n\tif (module === undefined || module === null) {\n\t\treturn module\n\t}\n\n\tconst result = flowModuleSchema.safeParse(module)\n\tif (!result.success) {\n\t\tconst errors = result.error.issues.slice(0, 5).map((issue) => {\n\t\t\tconst path = issue.path.length > 0 ? issue.path.join('.') : field\n\t\t\treturn `${path}: ${issue.message}`\n\t\t})\n\t\tthrow new Error(`Invalid ${field}:\\n${errors.join('\\n')}`)","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/windmill-labs/windmill/blob/e474e8803ce2ff5c2df09a58dab51d45f5c922ca/frontend/src/lib/components/copilot/chat/flow/core.ts#L232-L268","documentation":"parseOptionalJsonArg accepts a value that may already be parsed or a JSON string, and throws when JSON.parse of the string fails, embedding the underlying parser message. It is used by parsedModule and flowTools to coerce string tool-call arguments into objects.","triggerScenarios":"A tool argument for `field` arrives as a string that is not valid JSON — typically an LLM-produced tool call with truncated, single-quoted, or commented JSON — and typeof value === 'string'.","commonSituations":"Model emits JSON with trailing commas or unquoted keys; argument was truncated by a token limit; caller double-encoded (passed a JSON string of a JSON string) or passed plain text where JSON was expected.","solutions":["Validate/repair the JSON string before calling (JSON.parse in a try, or a lenient repair like jsonrepair).","Have the model retry the tool call with the argument as a proper JSON object rather than a string.","Check for truncation if the string looks cut off mid-structure and re-issue with fewer/larger chunks."],"exampleFix":"// before\nawait flowTools.updateFlow({ flow: rawStringFromModel })\n// after\nlet flowArg\ntry { flowArg = JSON.parse(rawStringFromModel) }\ncatch { flowArg = JSON.parse(jsonrepair(rawStringFromModel)) }\nawait flowTools.updateFlow({ flow: flowArg })","handlingStrategy":"validation","validationCode":"let parsed: unknown\nif (typeof value === 'string') {\n  try { parsed = JSON.parse(value) } catch { parsed = JSON.parse(jsonrepair(value)) }\n} else parsed = value","typeGuard":"function isJsonObject(v: unknown): v is Record<string, unknown> {\n  return typeof v === 'object' && v !== null && !Array.isArray(v)\n}","tryCatchPattern":"try {\n  await tool(args)\n} catch (e) {\n  if (String(e.message).startsWith('Invalid JSON for')) {\n    return requestModelRetryWithJsonInstruction(e.message)\n  }\n  throw e\n}","preventionTips":["Pass already-parsed objects to tool calls instead of JSON strings when possible.","Instruct the model to emit strict JSON (no trailing commas, double quotes).","Check for token-limit truncation when long JSON arguments fail to parse."],"tags":["json","parsing","validation","tool-arguments"],"backgroundTag":"invalid-json","analyzedSha":"e474e8803ce2ff5c2df09a58dab51d45f5c922ca","analyzedAt":"2026-09-03T12:38:19.024Z","contentChangedAt":"2026-09-03T12:38:19.024Z","schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}