Answers.Body: <p>When a route is accessed, <code>entry</code> isn't automatically defined.</p>
  
  <p>The actual value for <code>*</code> is available in the <code>any</code> variable in your template—see this example:</p>
  
  <pre><code>Route: projects/type/(*)
  Template: _test
  </code></pre>
  
  <pre><code>{# templates/_test.twig #}
  Substituted route param: {{ any }}
  </code></pre>
  
  <p>Do note that <code>entry</code> is not automatically set by Craft for any custom routes! It's your responsibility to take the incoming value (in your case, <code>any</code>) and look up the Entry, within the template, or bail if nothing is found:</p>
  
  <pre><code>{# We can totally skip the test for `any`, because this template is only loaded when there's a non-zero-length value in the route: #}
  {% set entry = craft.entries({ title: any }).one() %}
  
  {% if not entry %}
    {% exit 404 %}
  {% endif %}
  
  {# At this point, you've set `entry`, and can use it however you like! #}
  {{ entry.myFieldHandle }}
  </code></pre>
  
  <blockquote>
    <p>I'd recommend reviewing the requirements for your route, and consider using a more specific token in your route (i.e. <code>(slug)</code>), and matching based on a more stable value—titles can change, but IDs should stick around, and slugs are less prone to editing!</p>
  </blockquote>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-01-30T21:12:40.197Z
Answers.Text: I'm sure you're right about the route. I'll take 'em all out, see how it works, and re-do them. . Added some more code to my original Q. I actually do have a chunk of code that gets an entry from the URL. For client reasons, I've got some subpages on projects that do some template magic based on the url, e.g. ```/project/this-old-house``` and ```/projects/this-old-house/thumbnails```.
Answers.UserDisplayName: SamC
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2020-01-30T20:29:49.263Z
Answers.LastActivityDate: 2020-01-30T20:35:07.207Z
Answers.LastEditDate: 2020-01-30T20:35:07.207Z
Answers.UserDisplayName: August Miller
Body: <p>The <code>{% exit 404 %}</code> doesn't work right on routed templates. </p>
  
  <p>It's fine on pages that aren't affected by routes. Mysite.com/asdfasdf shows me the proper 404 page. </p>
  
  <p>I've got some routes configured like this:</p>
  
  <pre><code>URL: projects/type/*
  Template: _projects/category.twig
  
  URL: projects/*
  Template: _projects/entry.twig
  </code></pre>
  
  <p>In the top of entry.twig, I've got code that says:</p>
  
  <pre><code>{% set entrySlug = craft.app.request.getSegment(2) %}
  {% set entry = craft.entries.slug(entrySlug).one() %}
  
  {% if entry is not defined or entry is null %}
      {% exit 404 %}
  {% endif %}
  
  {# regular page template below here #}
  </code></pre>
  
  <p>mysite.com/projects/WorkingProject - this works right.
  mysite.com/projects/BrokenProjectLink - gives me a 500 error.</p>
  
  <p>When I turn on dev mode, the Yii debugger gives me a 404 ( HTTP 404 – Not Found – yii\web\NotFoundHttpException ), which is the right thing. But turning devmode off, I don't get the 404 page, I get my 500 Internal Server Error page instead.</p>
  
  <p>Again, 404s for pages that don't have any routing work fine. It's just things that are getting routed, and using the <code>{% exit 404 %}</code> code.</p>
  
  <p>This all worked in v3.3.20 and earlier, but it doesn't seem to work the same in Craft 3.4.0.2.</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2020-01-30T20:34:26.167Z
Comments.Text: Answered below, but I'm compelled to ask why the native Entry/Category routing doesn't suffice? If you've set up your Sections and Category Groups to use the native Element URI/routing system, you wouldn't need to perform manual lookups at all!
Comments.UserDisplayName: August Miller
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2020-01-30T21:00:43.347Z
Comments.Text: Yeah, it's because the categories and individual entries live in the same parent segment. I want everything that's /projects/type/ to use category, and /projects/<project name> to go to the actual project pages. (and I can't change that) With native routing, the /projects/type/non-existent-category, it tries to load the entry template, and gives the wrong sort of 404.
Comments.UserDisplayName: SamC
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2020-01-30T21:26:39.423Z
Comments.Text: This sounds like unusual behavior… Element templates should only be loaded if their complete URI matches the request (see the `elements_sites` table). Craft won't make any inference about the path down to your Entry when a specific one isn't found—it'll just continue on and look up a user-defined route (i.e. via the CP or `routes.php`).
Comments.UserDisplayName: August Miller
Tags: <craft3><routing><404>
Title: {% Exit 404 %} doesn't work right with routes
ThreadText: # {% Exit 404 %} doesn't work right with routes
  
  (Asked by: username_0 on 2020-01-30)
  
  The `{% exit 404 %}` doesn't work right on routed templates.
  
  It's fine on pages that aren't affected by routes. Mysite.com/asdfasdf shows me the proper 404 page.
  
  I've got some routes configured like this:
  
  ```
  URL: projects/type/*
  Template: _projects/category.twig
  
  URL: projects/*
  Template: _projects/entry.twig
  
  ```
  
  In the top of entry.twig, I've got code that says:
  
  ```
  {% set entrySlug = craft.app.request.getSegment(2) %}
  {% set entry = craft.entries.slug(entrySlug).one() %}
  
  {% if entry is not defined or entry is null %}
      {% exit 404 %}
  {% endif %}
  
  {# regular page template below here #}
  
  ```
  
  mysite.com/projects/WorkingProject - this works right.
  mysite.com/projects/BrokenProjectLink - gives me a 500 error.
  
  When I turn on dev mode, the Yii debugger gives me a 404 ( HTTP 404 – Not Found – yii\web\NotFoundHttpException ), which is the right thing. But turning devmode off, I don't get the 404 page, I get my 500 Internal Server Error page instead.
  
  Again, 404s for pages that don't have any routing work fine. It's just things that are getting routed, and using the `{% exit 404 %}` code.
  
  This all worked in v3.3.20 and earlier, but it doesn't seem to work the same in Craft 3.4.0.2.
  
  **Tags:** craft3, routing, 404
  
  > **Comments:**
  > **username_1**: Answered below, but I'm compelled to ask why the native Entry/Category routing doesn't suffice? If you've set up your Sections and Category Groups to use the native Element URI/routing system, you wouldn't need to perform manual lookups at all!  
  > **username_0**: Yeah, it's because the categories and individual entries live in the same parent segment. I want everything that's /projects/type/ to use category, and /projects/<project name> to go to the actual project pages. (and I can't change that) With native routing, the /projects/type/non-existent-category, it tries to load the entry template, and gives the wrong sort of 404.  
  > **username_1**: This sounds like unusual behavior… Element templates should only be loaded if their complete URI matches the request (see the `elements_sites` table). Craft won't make any inference about the path down to your Entry when a specific one isn't found—it'll just continue on and look up a user-defined route (i.e. via the CP or `routes.php`).  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2020-01-30. Score: 2
  
  When a route is accessed, `entry` isn't automatically defined.
  
  The actual value for `*` is available in the `any` variable in your template—see this example:
  
  ```
  Route: projects/type/(*)
  Template: _test
  
  ```
  
  ```
  {# templates/_test.twig #}
  Substituted route param: {{ any }}
  
  ```
  
  Do note that `entry` is not automatically set by Craft for any custom routes! It's your responsibility to take the incoming value (in your case, `any`) and look up the Entry, within the template, or bail if nothing is found:
  
  ```
  {# We can totally skip the test for `any`, because this template is only loaded when there's a non-zero-length value in the route: #}
  {% set entry = craft.entries({ title: any }).one() %}
  
  {% if not entry %}
    {% exit 404 %}
  {% endif %}
  
  {# At this point, you've set `entry`, and can use it however you like! #}
  {{ entry.myFieldHandle }}
  
  ```
  
  > I'd recommend reviewing the requirements for your route, and consider using a more specific token in your route (i.e. `(slug)`), and matching based on a more stable value—titles can change, but IDs should stick around, and slugs are less prone to editing!
  
  > **Comments:**
  > **username_0**: I'm sure you're right about the route. I'll take 'em all out, see how it works, and re-do them. . Added some more code to my original Q. I actually do have a chunk of code that gets an entry from the URL. For client reasons, I've got some subpages on projects that do some template magic based on the url, e.g. ```/project/this-old-house``` and ```/projects/this-old-house/thumbnails```.  
  
  ---
  
  