Should a cache tag only render array for an otherwise empty block work? I have a custom blocks that displays results based on an entity query. For some pages the correct result is blank, and I want to hide the block. 

When a return an empty array from the block's build() method it appears to cache more or less forever.

If I return a render array that just contains #cache values will that get honored, or will the lack of content invalidate those tags some place another the way?  

if (empty($relatedContent)) {
  return [
    '#cache' =&gt; [
      'contexts' =&gt; ['url'],
      'tags' =&gt; ['node_list'],
    ],
  ];
}


For what it's worth, I've been testing the idea and I'm running into issues, but it's not clear yet if that's related to this or some other problem.
You are right about this, you need content (in form of a render element) for the cache metadata to be recognized. But you don't need to worry about this, because BlockViewBuilder detects an empty block and adds a markup render element with an empty string:

public static function preRender($build) {
    ...
    if ($content !== NULL &amp;&amp; !Element::isEmpty($content)) {
      ...
    }
    else {
      // Abort rendering: render as the empty string and ensure this block is
      // render cached, so we can avoid the work of having to repeatedly
      // determine whether the block is empty. For instance, modifying or adding
      // entities could cause the block to no longer be empty.
      $build = [
        '#markup' =&gt; '',
        '#cache' =&gt; $build['#cache'],
      ];
      ...