cube-js/cube · error · UserError
Unable to decode query param as JSON, error
Error message
Unable to decode query param as JSON, error: ${e.message} What it means
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.
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.
Example fix
// before
const qs = `?query={"measures":["Orders.count"],}`; // trailing comma -> parse error
// after
const qs = `?query=${encodeURIComponent(JSON.stringify({ measures: ['Orders.count'] }))}`; Defensive patterns
Strategy: validation
Validate before calling
const json = JSON.stringify(query);
JSON.parse(json); // throws locally with a clear message before hitting the API
const url = `/cubejs-api/v1/load?query=${encodeURIComponent(json)}`; Type guard
function isJsonSafeQuery(q: unknown): q is Record<string, unknown> {
try { JSON.parse(JSON.stringify(q)); return typeof q === 'object' && q !== null; } catch { return false; }
} Try / catch
try {
JSON.parse(queryParam);
} catch (e) {
console.error('query param is not valid JSON:', e.message);
queryParam = JSON.stringify(defaultQuery);
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Invalid query format
- No job description provided
- Query param is required
- A user's selector doesn't match any of the pre-aggregations…
- Can't parse date
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/821448613c475c94.
Report an issue: GitHub.
Appendix: source
Thrown at packages/cubejs-api-gateway/src/gateway.ts:2452
if (message.isWrapper) {
res.set('Content-Type', 'application/json');
res.send(Buffer.from(await message.getFinalResult()));
} else {
res.json(message);
}
};
}
protected parseQueryParam(query: RequestQuery | 'undefined'): Query | Query[] {
if (!query || query === 'undefined') {
throw new UserError('Query param is required');
}
if (typeof query === 'string') {
try {
return JSON.parse(query) as Query | Query[];
} catch (e: any) {
throw new UserError(`Unable to decode query param as JSON, error: ${e.message}`);
}
}
return query as Query | Query[];
}
protected async getCompilerApi(context: RequestContext) {
return this.compilerApi(context);
}
protected async getAdapterApi(context: RequestContext) {
return this.adapterApi(context);
}
public async contextByReq(req: Request, securityContext, requestId: string): Promise<ExtendedRequestContext> {
req.securityContext = securityContext;
const extensions = typeof this.extendContext === 'function' ? await this.extendContext(req) : {};View on GitHub (pinned to 7d981676b3)