diff --git a/mercurial/templater.py b/mercurial/templater.py
--- a/mercurial/templater.py
+++ b/mercurial/templater.py
@@ -837,7 +837,10 @@ def shortest(context, mapping, args):
                                 # i18n: "shortest" is a keyword
                                 _("shortest() expects an integer minlength"))
 
-    cl = mapping['ctx']._repo.changelog
+    # _partialmatch() of filtered changelog could take O(len(repo)) time,
+    # which would be unacceptably slow. so we look for hash collision in
+    # unfiltered space, which means some hashes may be slightly longer.
+    cl = mapping['ctx']._repo.unfiltered().changelog
     def isvalid(test):
         try:
             if cl._partialmatch(test) is None:
diff --git a/tests/test-command-template.t b/tests/test-command-template.t
--- a/tests/test-command-template.t
+++ b/tests/test-command-template.t
@@ -3469,9 +3469,10 @@ Test shortest(node) with the repo having
   4:107
 
  node 'c562' should be unique if the other 'c562' nodes are hidden
+ (but we don't try the slow path to filter out hidden nodes for now)
 
   $ hg log -r 8 -T '{rev}:{node|shortest}\n'
-  8:c562
+  8:c5625
   $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
   8:c5625
   9:c5623