Returning alternate HTTP codes for unpublished node
You can try to do this earlier in an exception instead of a response subscriber. Extend HttpExceptionSubscriberBase, so you need less code to do this. Then replace the 403 with a 404 exception with the method $event-&gt;setException()

/src/EventSubscriber/Unpublished404Subscriber.php

&lt;?php

namespace Drupal\mymodule\EventSubscriber;

use Drupal\Core\EventSubscriber\HttpExceptionSubscriberBase;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;

class Unpublished404Subscriber extends HttpExceptionSubscriberBase {

  protected static function getPriority() {
    // set priority higher than 50 if you want to log "page not found"
    return 0;
  }

  protected function getHandledFormats() {
    return ['html'];
  }

  public function on403(GetResponseForExceptionEvent $event) {
    $request = $event-&gt;getRequest();
    if ($request-&gt;attributes-&gt;get('_route') == 'entity.node.canonical') {
      $event-&gt;setException(new NotFoundHttpException());
    }
  }

}


mymodule.services.yml:

services:
  mymodule.404:
    class: Drupal\mymodule\EventSubscriber\Unpublished404Subscriber
    arguments: []
    tags:
      - { name: event_subscriber }


This replaces all 403 exceptions for canonical node routes. You can get the node object $request-&gt;attributes-&gt;get('node') if you want to check if this is really because the node is unpublished.