{"record":{"id":"821448613c475c94","repo":"cube-js/cube","slug":"unable-to-decode-query-param-as-json-error-e-m","errorCode":null,"errorMessage":"Unable to decode query param as JSON, error: ${e.message}","messagePattern":"Unable to decode query param as JSON, error: (.+?)","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":2452,"sourceCode":"      if (message.isWrapper) {\n        res.set('Content-Type', 'application/json');\n        res.send(Buffer.from(await message.getFinalResult()));\n      } else {\n        res.json(message);\n      }\n    };\n  }\n\n  protected parseQueryParam(query: RequestQuery | 'undefined'): Query | Query[] {\n    if (!query || query === 'undefined') {\n      throw new UserError('Query param is required');\n    }\n\n    if (typeof query === 'string') {\n      try {\n        return JSON.parse(query) as Query | Query[];\n      } catch (e: any) {\n        throw new UserError(`Unable to decode query param as JSON, error: ${e.message}`);\n      }\n    }\n\n    return query as Query | Query[];\n  }\n\n  protected async getCompilerApi(context: RequestContext) {\n    return this.compilerApi(context);\n  }\n\n  protected async getAdapterApi(context: RequestContext) {\n    return this.adapterApi(context);\n  }\n\n  public async contextByReq(req: Request, securityContext, requestId: string): Promise<ExtendedRequestContext> {\n    req.securityContext = securityContext;\n\n    const extensions = typeof this.extendContext === 'function' ? await this.extendContext(req) : {};","sourceCodeStart":2434,"sourceCodeEnd":2470,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L2434-L2470","documentation":"When the `query` parameter arrives as a string, parseQueryParam JSON.parse's it; any parse failure (malformed JSON, single quotes, trailing commas, HTML error pages, URL-encoding issues) is rethrown as this UserError with the underlying JSON parser message appended. It means the query string reached the server but is not valid JSON.","triggerScenarios":"GET /cubejs-api/v1/load?query={measures:['x']} (unquoted keys / single quotes); double-encoded or incorrectly escaped JSON; query truncated by URL length limits; HTML injected by a proxy error page.","commonSituations":"Hand-writing query strings in curl without quoting; using JS object syntax instead of strict JSON; not URL-encoding the JSON so characters like {, }, \" are mangled; middleware truncating long query strings.","solutions":["Validate with JSON.parse on the client before sending, and send JSON.stringify(query) URL-encoded.","Fix syntax: strict JSON requires double-quoted keys and strings, no trailing commas.","For very large queries, switch to POST /load with the query in the JSON body to avoid URL encoding/length problems.","Read the appended e.message in the error to pinpoint the exact JSON syntax position."],"exampleFix":"// before\nconst qs = `?query={\"measures\":[\"Orders.count\"],}`; // trailing comma -> parse error\n// after\nconst qs = `?query=${encodeURIComponent(JSON.stringify({ measures: ['Orders.count'] }))}`;","handlingStrategy":"validation","validationCode":"const json = JSON.stringify(query);\nJSON.parse(json); // throws locally with a clear message before hitting the API\nconst url = `/cubejs-api/v1/load?query=${encodeURIComponent(json)}`;","typeGuard":"function isJsonSafeQuery(q: unknown): q is Record<string, unknown> {\n  try { JSON.parse(JSON.stringify(q)); return typeof q === 'object' && q !== null; } catch { return false; }\n}","tryCatchPattern":"try {\n  JSON.parse(queryParam);\n} catch (e) {\n  console.error('query param is not valid JSON:', e.message);\n  queryParam = JSON.stringify(defaultQuery);\n}","preventionTips":["Always build query strings with JSON.stringify, never hand-written JSON.","URL-encode the JSON (encodeURIComponent) to avoid character mangling.","Use POST with a JSON body for large queries to avoid URL encoding pitfalls.","Validate with JSON.parse on the client before sending."],"tags":["json","rest-api","request-validation"],"backgroundTag":"invalid-json-payload","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}