{"record":{"id":"688938e78b97e058","repo":"apolloconfig/apollo","slug":"access-is-denied-688938","errorCode":null,"errorMessage":"Access is denied","messagePattern":"Access is denied","errorType":"http","errorClass":"AccessDeniedException","httpStatus":403,"severity":"warning","filePath":"apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ReleaseController.java","lineNumber":140,"sourceCode":"    ConfigPublishEvent event = ConfigPublishEvent.instance();\n    event.withAppId(appId).withCluster(clusterName).withNamespace(namespaceName)\n        .withReleaseId(createdRelease.getId()).setGrayPublishEvent(true).setEnv(Env.valueOf(env));\n\n    publisher.publishEvent(event);\n\n    return createdRelease;\n  }\n\n  @GetMapping(\"/envs/{env}/releases/{releaseId}\")\n  public ReleaseDTO get(@PathVariable String env, @PathVariable long releaseId) {\n    ReleaseDTO release = releaseService.findReleaseById(Env.valueOf(env), releaseId);\n\n    if (release == null) {\n      throw NotFoundException.releaseNotFound(releaseId);\n    }\n    if (unifiedPermissionValidator.shouldHideConfigToCurrentUser(release.getAppId(), env,\n        release.getClusterName(), release.getNamespaceName())) {\n      throw new AccessDeniedException(\"Access is denied\");\n    }\n    return release;\n  }\n\n  @GetMapping(\n      value = \"/apps/{appId}/envs/{env}/clusters/{clusterName}/namespaces/{namespaceName}/releases/all\")\n  public List<ReleaseBO> findAllReleases(@PathVariable String appId, @PathVariable String env,\n      @PathVariable String clusterName, @PathVariable String namespaceName,\n      @Valid @PositiveOrZero(message = \"page should be positive or 0\")\n      @RequestParam(defaultValue = \"0\") int page,\n      @Valid @Positive(message = \"size should be positive number\")\n      @RequestParam(defaultValue = \"5\") int size) {\n    if (unifiedPermissionValidator.shouldHideConfigToCurrentUser(appId, env, clusterName,\n        namespaceName)) {\n      return Collections.emptyList();\n    }\n\n    return releaseService.findAllReleases(appId, Env.valueOf(env), clusterName, namespaceName, page,","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/apolloconfig/apollo/blob/d95fc18d112589efc09ddcbe1507047584d55251/apollo-portal/src/main/java/com/ctrip/framework/apollo/portal/controller/ReleaseController.java#L122-L158","documentation":"AccessDeniedException (HTTP 403) from ReleaseController.get (GET /envs/{env}/releases/{releaseId}). After loading the release, if unifiedPermissionValidator.shouldHideConfigToCurrentUser(...) is true for the release's appId/env/cluster/namespace, the config is hidden and access is denied with this generic message (no details leaked).","triggerScenarios":"GET /envs/{env}/releases/{releaseId} by a user who is permitted to authenticate but is not allowed to view that namespace's config (role-based config visibility hides it).","commonSituations":"A user belonging to an app but without view-config rights on a restricted namespace; cross-team visibility rules; a service account without the view role.","solutions":["Request view-config permission on the release's appId/env/cluster/namespace.","Confirm the releaseId belongs to a namespace you are authorized to see.","Use an account that holds the appropriate role for that app.","If unexpected, audit the role assignments and the shouldHideConfigToCurrentUser rule."],"exampleFix":"// No code fix: authorization gate. Gain view-config permission on the target namespace, or query a release you are authorized to read.","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Reading a release can 403 when config is hidden from the current user.\ntry {\n  ReleaseDTO r = portal.getRelease(env, releaseId);\n} catch (HttpClientErrorException.Forbidden e) {\n  // 'Access is denied' - user lacks view-config permission on that namespace\n  requestViewConfigPermission(r_appId, r_namespace); // from a prior allowed lookup\n}","preventionTips":["Only query releases for namespaces your account can view.","Use an account holding view-config permission for cross-app tooling.","Treat a 403 here as expected for hidden namespaces, not a bug.","Audit shouldHideConfigToCurrentUser rules if access is unexpected."],"tags":["permission","access-denied","release","config-visibility","role"],"backgroundTag":null,"analyzedSha":"d95fc18d112589efc09ddcbe1507047584d55251","analyzedAt":"2026-08-14T04:00:05.477Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}