{"record":{"id":"f24aa4264f9fe602","repo":"cube-js/cube","slug":"maskedmembers-cannot-be-provided-in-the-query","errorCode":null,"errorMessage":"maskedMembers cannot be provided in the query","messagePattern":"maskedMembers cannot be provided in the query","errorType":"validation","errorClass":"UserError","httpStatus":null,"severity":"error","filePath":"packages/cubejs-api-gateway/src/gateway.ts","lineNumber":1448,"sourceCode":"    const startTime = new Date().getTime();\n    const compilerApi = await this.getCompilerApi(context);\n\n    const queryNormalizationResult: Array<{\n      normalizedQuery: NormalizedQuery,\n      hasExpressionsInQuery: boolean\n    }> = queries.map((currentQuery) => {\n      const hasExpressionsInQuery = this.hasExpressionsInQuery(currentQuery);\n\n      if (hasExpressionsInQuery) {\n        if (!memberExpressions) {\n          throw new Error('Expressions are not allowed in this context');\n        }\n\n        currentQuery = this.parseMemberExpressionsInQuery(currentQuery);\n      }\n\n      if ((currentQuery as any).maskedMembers) {\n        throw new UserError('maskedMembers cannot be provided in the query');\n      }\n\n      return {\n        normalizedQuery: (normalizeQuery(currentQuery, persistent, cacheMode)),\n        hasExpressionsInQuery\n      };\n    });\n\n    let normalizedQueries: NormalizedQuery[] = await Promise.all(\n      queryNormalizationResult.map(\n        async ({ normalizedQuery, hasExpressionsInQuery }) => {\n          let evaluatedQuery: Query | NormalizedQuery = normalizedQuery;\n\n          if (hasExpressionsInQuery) {\n            // We need to parse/eval all member expressions early as applyRowLevelSecurity\n            // needs to access the full SQL query in order to evaluate rules\n            evaluatedQuery = this.evalMemberExpressionsInQuery(normalizedQuery);\n          }","sourceCodeStart":1430,"sourceCodeEnd":1466,"githubUrl":"https://github.com/cube-js/cube/blob/7d981676b36392fec34088b9afab6bdcad40207c/packages/cubejs-api-gateway/src/gateway.ts#L1430-L1466","documentation":"Cube's REST API rejects any query body containing a `maskedMembers` property. maskedMembers is an internal mechanism used to hide member-level data based on security contexts; it must be computed server-side, never supplied by the client. Sending it from the client is treated as an attempt to bypass security masking, so the gateway fails fast with a UserError before normalizing the query.","triggerScenarios":"POST /cubejs-api/v1/load (or /v1/sql) with a query JSON object that includes a `maskedMembers` key; the check runs in getNormalizedQueries after member expression parsing whenever (currentQuery as any).maskedMembers is truthy.","commonSituations":"Copying a query captured from Cube's internal/SQL API traffic (which includes maskedMembers) and replaying it against the REST API; saving a serialized query from a debug log or IDE devtools dump that included internal fields; older or hand-written integrations that mirrored server-normalized query objects.","solutions":["Remove the `maskedMembers` key from the query object before sending it to the API.","Sanitize queries captured from internal traffic/logs: keep only public fields (measures, dimensions, timeDimensions, filters, segments, order, limit, offset).","If you need member masking, configure it server-side via security contexts / member visibility so Cube computes maskedMembers itself."],"exampleFix":"// before\nawait cubeApi.load({ maskedMembers: ['orders.total'], measures: ['orders.count'] });\n// after\nawait cubeApi.load({ measures: ['orders.count'] });","handlingStrategy":"validation","validationCode":"const PUBLIC_QUERY_KEYS = ['measures','dimensions','timeDimensions','segments','filters','order','limit','offset','timezone','renewQuery','ungrouped'];\nfunction isQuerySafe(q) { return q != null && Object.keys(q).every(k => PUBLIC_QUERY_KEYS.includes(k)); }\nif (!isQuerySafe(query)) throw new Error('Query contains internal fields like maskedMembers');","typeGuard":"function hasMaskedMembers(q: unknown): q is { maskedMembers: unknown } {\n  return typeof q === 'object' && q !== null && 'maskedMembers' in q;\n}","tryCatchPattern":"try {\n  await cubeApi.load(query);\n} catch (e) {\n  if (String(e?.message).includes('maskedMembers')) {\n    const { maskedMembers, ...clean } = query;\n    await cubeApi.load(clean); // retry without internal fields\n  } else throw e;\n}","preventionTips":["Never replay queries captured from internal SQL API traffic or server logs verbatim.","Serialize queries through a whitelist of public fields before sending.","Keep the official client SDK; it does not emit maskedMembers."],"tags":["rest-api","query-validation","security"],"backgroundTag":"internal-field-in-public-query","analyzedSha":"7d981676b36392fec34088b9afab6bdcad40207c","analyzedAt":"2026-09-02T03:45:10.400Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}