diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -13,6 +13,72 @@
     return $this->project;
   }
 
+  protected function loadProject() {
+    $viewer = $this->getViewer();
+    $request = $this->getRequest();
+
+    $id = $request->getURIData('id');
+    $slug = $request->getURIData('slug');
+
+    if ($slug) {
+      $normal_slug = PhabricatorSlug::normalizeProjectSlug($slug);
+      $is_abnormal = ($slug !== $normal_slug);
+      $normal_uri = "/tag/{$normal_slug}/";
+    } else {
+      $is_abnormal = false;
+    }
+
+    $query = id(new PhabricatorProjectQuery())
+      ->setViewer($viewer)
+      ->needMembers(true)
+      ->needWatchers(true)
+      ->needImages(true)
+      ->needSlugs(true);
+
+    if ($slug) {
+      $query->withSlugs(array($slug));
+    } else {
+      $query->withIDs(array($id));
+    }
+
+    $policy_exception = null;
+    try {
+      $project = $query->executeOne();
+    } catch (PhabricatorPolicyException $ex) {
+      $policy_exception = $ex;
+      $project = null;
+    }
+
+    if (!$project) {
+      // This project legitimately does not exist, so just 404 the user.
+      if (!$policy_exception) {
+        return new Aphront404Response();
+      }
+
+      // Here, the project exists but the user can't see it. If they are
+      // using a non-canonical slug to view the project, redirect to the
+      // canonical slug. If they're already using the canonical slug, rethrow
+      // the exception to give them the policy error.
+      if ($is_abnormal) {
+        return id(new AphrontRedirectResponse())->setURI($normal_uri);
+      } else {
+        throw $policy_exception;
+      }
+    }
+
+    // The user can view the project, but is using a noncanonical slug.
+    // Redirect to the canonical slug.
+    $primary_slug = $project->getPrimarySlug();
+    if ($slug && ($slug !== $primary_slug)) {
+      $primary_uri = "/tag/{$primary_slug}/";
+      return id(new AphrontRedirectResponse())->setURI($primary_uri);
+    }
+
+    $this->setProject($project);
+
+    return null;
+  }
+
   public function buildApplicationMenu() {
     return $this->buildSideNavView(true)->getMenu();
   }
diff --git a/src/applications/project/controller/PhabricatorProjectFeedController.php b/src/applications/project/controller/PhabricatorProjectFeedController.php
--- a/src/applications/project/controller/PhabricatorProjectFeedController.php
+++ b/src/applications/project/controller/PhabricatorProjectFeedController.php
@@ -8,38 +8,25 @@
   }
 
   public function handleRequest(AphrontRequest $request) {
-    $user = $request->getUser();
+    $viewer = $request->getUser();
 
-    $query = id(new PhabricatorProjectQuery())
-      ->setViewer($user)
-      ->needMembers(true)
-      ->needWatchers(true)
-      ->needImages(true)
-      ->needSlugs(true);
-    $id = $request->getURIData('id');
-    $slug = $request->getURIData('slug');
-    if ($slug) {
-      $query->withSlugs(array($slug));
-    } else {
-      $query->withIDs(array($id));
-    }
-    $project = $query->executeOne();
-    if (!$project) {
-      return new Aphront404Response();
-    }
-    if ($slug && $slug != $project->getPrimarySlug()) {
-      return id(new AphrontRedirectResponse())
-        ->setURI('/tag/'.$project->getPrimarySlug().'/');
+    $response = $this->loadProject();
+    if ($response) {
+      return $response;
     }
 
-    $query = new PhabricatorFeedQuery();
-    $query->setFilterPHIDs(
-      array(
-        $project->getPHID(),
-      ));
-    $query->setLimit(50);
-    $query->setViewer($request->getUser());
-    $stories = $query->execute();
+    $project = $this->getProject();
+    $id = $project->getID();
+
+    $stories = id(new PhabricatorFeedQuery())
+      ->setViewer($viewer)
+      ->setFilterPHIDs(
+        array(
+          $project->getPHID(),
+        ))
+      ->setLimit(50)
+      ->execute();
+
     $feed = $this->renderStories($stories);
 
     $box = id(new PHUIObjectBoxView())
@@ -57,21 +44,6 @@
       ));
   }
 
-  private function renderFeedPage(PhabricatorProject $project) {
-
-    $query = new PhabricatorFeedQuery();
-    $query->setFilterPHIDs(array($project->getPHID()));
-    $query->setViewer($this->getRequest()->getUser());
-    $query->setLimit(100);
-    $stories = $query->execute();
-
-    if (!$stories) {
-      return pht('There are no stories about this project.');
-    }
-
-    return $this->renderStories($stories);
-  }
-
   private function renderStories(array $stories) {
     assert_instances_of($stories, 'PhabricatorFeedStory');
 
@@ -85,5 +57,4 @@
       $view->render());
   }
 
-
 }
diff --git a/src/applications/project/controller/PhabricatorProjectMembersEditController.php b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
--- a/src/applications/project/controller/PhabricatorProjectMembersEditController.php
+++ b/src/applications/project/controller/PhabricatorProjectMembersEditController.php
@@ -12,10 +12,6 @@
       ->withIDs(array($id))
       ->needMembers(true)
       ->needImages(true)
-      ->requireCapabilities(
-        array(
-          PhabricatorPolicyCapability::CAN_VIEW,
-        ))
       ->executeOne();
     if (!$project) {
       return new Aphront404Response();
diff --git a/src/applications/project/controller/PhabricatorProjectProfileController.php b/src/applications/project/controller/PhabricatorProjectProfileController.php
--- a/src/applications/project/controller/PhabricatorProjectProfileController.php
+++ b/src/applications/project/controller/PhabricatorProjectProfileController.php
@@ -8,35 +8,20 @@
   }
 
   public function handleRequest(AphrontRequest $request) {
-    $user = $request->getUser();
-
-    $query = id(new PhabricatorProjectQuery())
-      ->setViewer($user)
-      ->needMembers(true)
-      ->needWatchers(true)
-      ->needImages(true)
-      ->needSlugs(true);
-    $id = $request->getURIData('id');
-    $slug = $request->getURIData('slug');
-    if ($slug) {
-      $query->withSlugs(array($slug));
-    } else {
-      $query->withIDs(array($id));
-    }
-    $project = $query->executeOne();
-    if (!$project) {
-      return new Aphront404Response();
-    }
-    if ($slug && $slug != $project->getPrimarySlug()) {
-      return id(new AphrontRedirectResponse())
-        ->setURI('/tag/'.$project->getPrimarySlug().'/');
+    $viewer = $request->getUser();
+
+    $response = $this->loadProject();
+    if ($response) {
+      return $response;
     }
 
+    $project = $this->getProject();
+    $id = $project->getID();
     $picture = $project->getProfileImageURI();
 
     $header = id(new PHUIHeaderView())
       ->setHeader($project->getName())
-      ->setUser($user)
+      ->setUser($viewer)
       ->setPolicyObject($project)
       ->setImage($picture);
 
@@ -60,15 +45,13 @@
 
     $nav = $this->buildIconNavView($project);
     $nav->selectFilter("profile/{$id}/");
-    $nav->appendChild($object_box);
-    $nav->appendChild($timeline);
-
-    return $this->buildApplicationPage(
-      $nav,
-      array(
-        'title' => $project->getName(),
-        'pageObjects' => array($project->getPHID()),
-      ));
+
+    return $this->newPage()
+      ->setNavigation($nav)
+      ->setTitle($project->getName())
+      ->setPageObjectPHIDs(array($project->getPHID()))
+      ->appendChild($object_box)
+      ->appendChild($timeline);
   }
 
   private function buildActionListView(PhabricatorProject $project) {
diff --git a/src/applications/project/controller/PhabricatorProjectViewController.php b/src/applications/project/controller/PhabricatorProjectViewController.php
--- a/src/applications/project/controller/PhabricatorProjectViewController.php
+++ b/src/applications/project/controller/PhabricatorProjectViewController.php
@@ -11,31 +11,11 @@
     $request = $this->getRequest();
     $viewer = $request->getViewer();
 
-    $query = id(new PhabricatorProjectQuery())
-      ->setViewer($viewer)
-      ->needMembers(true)
-      ->needWatchers(true)
-      ->needImages(true)
-      ->needSlugs(true);
-    $id = $request->getURIData('id');
-    $slug = $request->getURIData('slug');
-    if ($slug) {
-      $query->withSlugs(array($slug));
-    } else {
-      $query->withIDs(array($id));
-    }
-    $project = $query->executeOne();
-    if (!$project) {
-
-      // If this request corresponds to a project but just doesn't have the
-      // slug quite right, redirect to the proper URI.
-      $uri = $this->getNormalizedURI($slug);
-      if ($uri !== null) {
-        return id(new AphrontRedirectResponse())->setURI($uri);
-      }
-
-      return new Aphront404Response();
+    $response = $this->loadProject();
+    if ($response) {
+      return $response;
     }
+    $project = $this->getProject();
 
     $columns = id(new PhabricatorProjectColumnQuery())
       ->setViewer($viewer)
@@ -60,31 +40,4 @@
     return $this->delegateToController($controller_object);
   }
 
-  private function getNormalizedURI($slug) {
-    if (!strlen($slug)) {
-      return null;
-    }
-
-    $normal = PhabricatorSlug::normalizeProjectSlug($slug);
-    if ($normal === $slug) {
-      return null;
-    }
-
-    $viewer = $this->getViewer();
-
-    // Do execute() instead of executeOne() here so we canonicalize before
-    // raising a policy exception. This is a little more polished than letting
-    // the user hit the error on any variant of the slug.
-
-    $projects = id(new PhabricatorProjectQuery())
-      ->setViewer($viewer)
-      ->withSlugs(array($normal))
-      ->execute();
-    if (!$projects) {
-      return null;
-    }
-
-    return "/tag/{$normal}/";
-  }
-
 }