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

  1. Validate with JSON.parse on the client before sending, and send JSON.stringify(query) URL-encoded.
  2. Fix syntax: strict JSON requires double-quoted keys and strings, no trailing commas.
  3. For very large queries, switch to POST /load with the query in the JSON body to avoid URL encoding/length problems.
  4. 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

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

Related errors


AI-assisted analysis of cube-js/cube@7d981676b3 (2026-09-02). Data as JSON: /api/errors/821448613c475c94. Report an issue: GitHub.