cube-js/cube · error · UserError
Unable to decode query param as JSON, error: ${e.message}
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.
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)
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: ${error.message || error.toString()}
- No job description provided
- Query param is required
- Can't parse date: '${from}'
- Can't parse date: '${to}'
AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02).
Data as JSON: /api/errors/821448613c475c94.
Report an issue: GitHub.