react-router: [v6][Bug]: HashRouter and wildcard route "*" does not match when provided with URL with characters between "#" and "/" eg. "#unknown/"

What version of React Router are you using?

6.2.1

Steps to Reproduce

<HashRouter>
	<Routes>
		<Route path="world" element={"Hello World"} />
		<Route path="*" element={"World not found"} />
	</Routes>
</HashRouter>

And navigate to hash #unknown/world

Expected Behavior

I expect World not found to be rendered. I expect wildcard route to match every unknown path so I can notify user about the problem.

Actual Behavior

Wildcard route <Route path="*" does not match. Shows blank page.

This issue is possibly related to issues #8428 and #8517, but neither mentions HashRouter explicitly. The closest described issue is @vreezy’s https://github.com/remix-run/react-router/issues/8428#issuecomment-985402731

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Reactions: 5
  • Comments: 18 (8 by maintainers)

Most upvoted comments

This is resolved by #10753 and will be available in the next release

Btw my workaround:

   useEffect(() => {
      if(window.location.hash.indexOf("#%") > -1 ) { 
         window.location.hash = ""; 
      }
   });

I’ve come across this issue also. I tried your work-around approach, but with no luck. So I’ve come up with my own solution (for anyone who might find this thread useful):

const InvalidHashRouteCatcher = ({ regex, children }: InvalidHashRouteCatcherProps) => {
    const navigate = useNavigate();
    useEffect(() => {
        const match = window?.location?.hash.match(regex);
        if (match && match.length) {
            navigate(`/${match[0].replace("#", "")}`);
        }
    });

    return <>{children}</>;
};

So you can do this in you code:

<HashRouter>
    <InvalidHashRouteCatcher regex={/#\w+/gi}>
        <Routes>
                              ...
        </Routes>
    </InvalidHashRouteCatcher>
</HashRouter>

But I think this should be fixed in the Router itself. Or at least being able to catch the “No route matches…” warning.

In HashRouter, I face similar problems in the following structure

<HashRouter>
        <Routes>
          <Route path="/" element={<Layout/>}>
            <Route index element={<HomePage/>} />
            <Route path='xxx' element={<XXX/>} />
            <Route path='*' element={<ErrorPage/>} />
          </Route>
        </Routes>
</HashRouter>

In the above structure, it works as follows:

✔matched by path='*', work fine

'https://localhost:8000/#/unknown'
'https://localhost:8000/#/unknown/123'

---
❓expected to be matched by path='*';
but actually is matched by outer path='/' and shows index element

'https://localhost:8000/unknown'
'https://localhost:8000/@'
'https://localhost:8000/@unknown'

---
❌failed, shows blank pages,
throws 'No routes matched location "unknown" ' warns.

'https://localhost:8000/#unknown'
'https://localhost:8000/#unknown/123'

(a server error will occur for URLs like 'https://localhost:8000/@/unknown', 'https://localhost:8000/unknown/123',)

expected behavior

path='*' should match following

'https://localhost:8000/#unknown'
'https://localhost:8000/#unknown/123'
'https://localhost:8000/unknown'
'https://localhost:8000/@'
'https://localhost:8000/@unknown'

index element should only be shown when the URL is

'https://localhost:8000/'

Btw my workaround:

   useEffect(() => {
      if(window.location.hash.indexOf("#%") > -1 ) { 
         window.location.hash = ""; 
      }
   });