{"record":{"id":"be0c7a7d1fd1b6de","repo":"getredash/redash","slug":"query-id-not-found","errorCode":null,"errorMessage":"Query id {} not found.","messagePattern":"Query id (.+?) not found\\.","errorType":"exception","errorClass":"PermissionError","httpStatus":403,"severity":"error","filePath":"redash/query_runner/query_results.py","lineNumber":49,"sourceCode":"def extract_query_params(query):\n    return re.findall(r\"(?:join|from)\\s+param_query_(\\d+)_{([^}]+)}\", query, re.IGNORECASE)\n\n\ndef extract_query_ids(query):\n    queries = re.findall(r\"(?:join|from)\\s+query_(\\d+)\", query, re.IGNORECASE)\n    return [int(q) for q in queries]\n\n\ndef extract_cached_query_ids(query):\n    queries = re.findall(r\"(?:join|from)\\s+cached_query_(\\d+)\", query, re.IGNORECASE)\n    return [int(q) for q in queries]\n\n\ndef _load_query(user, query_id):\n    query = models.Query.get_by_id(query_id)\n\n    if user.org_id != query.org_id:\n        raise PermissionError(\"Query id {} not found.\".format(query.id))\n\n    # TODO: this duplicates some of the logic we already have in the redash.handlers.query_results.\n    # We should merge it so it's consistent.\n    if not has_access(query.data_source, user, view_only):\n        raise PermissionError(\"You do not have access to query id {}.\".format(query.id))\n\n    return query\n\n\ndef replace_query_parameters(query_text, params):\n    qs = parse_qs(params)\n    for key, value in qs.items():\n        query_text = query_text.replace(\"{{{{{my_key}}}}}\".format(my_key=key), value[0])\n    return query_text\n\n\ndef get_query_results(user, query_id, bring_from_cache, params=None):\n    query = _load_query(user, query_id)","sourceCodeStart":31,"sourceCodeEnd":67,"githubUrl":"https://github.com/getredash/redash/blob/ca79fe988d81cdac9675b412f3dfcab107bc1fbc/redash/query_runner/query_results.py#L31-L67","documentation":"Raised by _load_query (redash/query_runner/query_results.py:49) as a PermissionError when the requested query exists but belongs to a different organization than the requesting user. Redash is multi-tenant by org_id, and cross-org access is treated as 'not found' to avoid leaking the existence of queries in other tenants.","triggerScenarios":"Calling get_query_results(user, query_id, ...) or the Python `query_results` query runner with a query id whose org_id differs from user.org_id — e.g. a query id copied from another Redash instance or another account's URL.","commonSituations":"Copy-pasting a query id or full query URL between staging/production or between two separate Redash installations; stale hardcoded query ids after a data migration or org restructure; tests that create users and queries under different orgs.","solutions":["Verify the query id belongs to the same Redash instance/account the user is on (open /queries/<id> in the UI)","Update the hardcoded query id in the calling query/python script to one from the current org","In tests, create both the user and the query under the same org (models.Query created with the user's org)"],"exampleFix":"# before (test)\nuser = factory.create_user(org=factory.create_org())\nquery = factory.create_query(org=self.org)\n# after\nuser = factory.create_user(org=self.org)\nquery = factory.create_query(org=self.org)","handlingStrategy":"try-catch","validationCode":"query = models.Query.get_by_id(query_id)\nif query is None or query.org_id != user.org_id:\n    return error_response(404, 'query not found')","typeGuard":null,"tryCatchPattern":"try:\n    results = get_query_results(user, qid, bring_from_cache)\nexcept PermissionError as e:\n    return error_response(404, str(e))  # treat cross-org as not found\nexcept Exception as e:\n    return error_response(400, str(e))","preventionTips":["Store query ids alongside the org/instance they came from; never hardcode cross-instance ids","In tests, always create user and query with factory helpers that share the default org","Validate ids from user input against the current org before calling loaders"],"tags":["redash","permissions","multi-tenant","query-runner"],"backgroundTag":"permission-denied","analyzedSha":"ca79fe988d81cdac9675b412f3dfcab107bc1fbc","analyzedAt":"2026-08-28T18:32:34.637Z","schemaVersion":2},"datasetVersion":"2026-08-28T21:17:43.275Z"}