{"record":{"id":"41bee9cb55b3ce39","repo":"ToolJet/ToolJet","slug":"invalid-json-message","errorCode":null,"errorMessage":"Invalid JSON message","messagePattern":"Invalid JSON message","errorType":"validation","errorClass":"QueryError","httpStatus":null,"severity":"error","filePath":"plugins/packages/grpc/lib/index.ts","lineNumber":54,"sourceCode":"    if (authType === 'basic') {\n      metadata.add('username', sourceOptions.username);\n      metadata.add('password', sourceOptions.password);\n    }\n\n    if (authType === 'bearer') {\n      metadata.add('Authorization', `Bearer ${sourceOptions.bearer_token}`);\n    }\n\n    if (authType === 'api_key') {\n      metadata.add(sourceOptions.grpc_apikey_key, sourceOptions.grpc_apikey_value);\n    }\n\n    let jsonMessage = {};\n    if (queryOptions.jsonMessage) {\n      try {\n        jsonMessage = JSON.parse(queryOptions.jsonMessage);\n      } catch (e) {\n        throw new QueryError('Invalid JSON message', {}, {});\n      }\n    }\n\n    const result = await new Promise((resolve, reject) => {\n      clientStub[rpc](jsonMessage, metadata, (err: any, response: any) => {\n        if (err) {\n          reject(err);\n        }\n        resolve(response);\n      });\n    }).catch((err) => {\n      throw new QueryError(err.message, {}, {});\n    });\n\n    return {\n      status: 'ok',\n      data: result as any,\n    };","sourceCodeStart":36,"sourceCodeEnd":72,"githubUrl":"https://github.com/ToolJet/ToolJet/blob/20602a8e101f2e59686c9afde0d1402aac2c8871/plugins/packages/grpc/lib/index.ts#L36-L72","documentation":"QueryError thrown by the legacy grpc plugin when queryOptions.jsonMessage is present but JSON.parse fails. The rpc call needs a JSON object as its request payload, so a syntactically invalid string is rejected before invoking the method. The error carries empty objects for data and metadata, so the original parse message is lost.","triggerScenarios":"User enters a request message with a trailing comma, single quotes, or unquoted keys; copy/paste of a JS object literal instead of JSON; an empty-but-non-empty string of whitespace past the truthiness check.","commonSituations":"Query editor with hand-typed JSON; payload templated with a variable that rendered to invalid JSON; mixing JS syntax (undefined, comments) into the message.","solutions":["Validate the message parses as JSON before calling run (JSON.parse in a try/catch).","Use strict JSON: double quotes, no trailing commas, no comments, no undefined.","If the payload contains variables, render then re-validate before sending."],"exampleFix":"// before\nrun(srcOpts, { serviceName, rpc, jsonMessage: \"{name: 'foo',}\" });\n// after\nrun(srcOpts, { serviceName, rpc, jsonMessage: '{\"name\":\"foo\"}' });","handlingStrategy":"validation","validationCode":"function parseJsonMessage(raw: string): Record<string, unknown> {\n  try {\n    return JSON.parse(raw);\n  } catch {\n    throw new Error('jsonMessage is not valid JSON');\n  }\n}\nif (queryOptions.jsonMessage) parseJsonMessage(queryOptions.jsonMessage);\nawait grpcPlugin.run(sourceOptions, queryOptions, dataSourceId);","typeGuard":"const isJsonString = (s: string): boolean => {\n  try { JSON.parse(s); return true; } catch { return false; }\n};","tryCatchPattern":"try {\n  await grpcPlugin.run(sourceOptions, queryOptions, dataSourceId);\n} catch (e) {\n  if (e instanceof QueryError && e.message === 'Invalid JSON message') {\n    surfaceJsonError(queryOptions.jsonMessage);\n  }\n  throw e;\n}","preventionTips":["Lint the request message as JSON in the editor.","Render templated variables then re-validate before send.","Avoid JS-only syntax (single quotes, comments, undefined)."],"tags":["grpc","validation","json"],"backgroundTag":null,"analyzedSha":"20602a8e101f2e59686c9afde0d1402aac2c8871","analyzedAt":"2026-08-13T05:58:54.221Z","schemaVersion":2},"datasetVersion":"2026-08-13T09:17:06.757Z"}