getredash/redash · error

Please use a user API key.

Error message

Please use a user API key.

What it means

Raised by QueryResource.post (the query execution/result-job endpoint) in redash/handlers/queries.py when the request authenticates with a query-scoped API key (is_api_user()). Executing or refreshing queries requires a user API key because only a real user can hold modify permissions.

Source

Thrown at redash/handlers/queries.py:461

        self.record_event({"action": "fork", "object_id": query_id, "object_type": "query"})

        return QuerySerializer(forked_query, with_visualizations=True).serialize()


class QueryRefreshResource(BaseResource):
    def post(self, query_id):
        """
        Execute a query, updating the query object with the results.

        :param query_id: ID of query to execute

        Responds with query task details.
        """
        # TODO: this should actually check for permissions, but because currently you can only
        # get here either with a user API key or a query one, we can just check whether it's
        # an api key (meaning this is a query API key, which only grants read access).
        if self.current_user.is_api_user():
            abort(403, message="Please use a user API key.")

        query = get_object_or_404(models.Query.get_by_id_and_org, query_id, self.current_org)
        require_access(query, self.current_user, not_view_only)

        parameter_values = collect_parameters_from_request(request.args)
        parameterized_query = ParameterizedQuery(query.query_text, org=self.current_org)
        should_apply_auto_limit = query.options.get("apply_auto_limit", False)
        return run_query(parameterized_query, parameter_values, query.data_source, query.id, should_apply_auto_limit)


class QueryTagsResource(BaseResource):
    def get(self):
        """
        Returns all query tags including those for drafts.
        """
        tags = models.Query.all_tags(self.current_user, include_drafts=True)
        return {"tags": [{"name": name, "count": count} for name, count in tags]}

View on GitHub (pinned to ca79fe988d)

Solutions

  1. Use your personal user API key (found in the user profile Settings page, or via the users API).
  2. If embedding read-only access was the goal, use the query result endpoint (GET latest result) which permits query API keys.
  3. Store the key under a distinct env var (e.g. REDASH_USER_API_KEY) to avoid mixing key types.

Example fix

# before
headers = {'Authorization': 'Key <query-scoped-api-key>'}
client.post('/api/queries/123/refresh', headers=headers)

# after
headers = {'Authorization': 'Key <user-api-key>'}
client.post('/api/queries/123/refresh', headers=headers)
Defensive patterns

Strategy: validation

Validate before calling

# check key type: query keys fail execution, user keys work
who = client.get('/api/session')
assert not who.get('is_api_user', False) or 'query' not in key_scope

Try / catch

try:
    client.post(f'/api/queries/{qid}/refresh', headers=h)
except HTTPError as e:
    if e.response.status_code == 403 and 'user API key' in e.response.text:
        h['Authorization'] = f'Key {os.environ["REDASH_USER_API_KEY"]}'
        client.post(f'/api/queries/{qid}/refresh', headers=h)
    else:
        raise

Prevention

When it happens

Trigger: POST /api/queries/<id>/results (or /refresh) using the API key shown on a query's sharing dialog instead of the user profile API key.

Common situations: Copy-pasting the wrong key from the UI (query key vs personal key); CI jobs configured with a share key attempting to trigger executions; scripts written against read-only endpoints later upgraded to trigger execution with the same key.

Related errors


AI-assisted analysis of getredash/redash@ca79fe988d (2026-08-28). Data as JSON: /api/errors/38d678c9355bd367. Report an issue: GitHub.