diff --git a/src/app/components/editor/input.ts b/src/app/components/editor/input.ts
index 29e5bd6a..20c56ed3 100644
--- a/src/app/components/editor/input.ts
+++ b/src/app/components/editor/input.ts
@@ -25,6 +25,7 @@ import {
   parseMatrixToUser,
   testMatrixTo,
 } from '../../plugins/matrix-to';
+import { tryDecodeURIComponent } from '../../utils/dom';
 
 const markNodeToType: Record<string, MarkType> = {
   b: MarkType.Bold,
@@ -73,7 +74,7 @@ const elementToInlineNode = (node: Element): MentionElement | EmoticonElement |
     return createEmoticonElement(src, alt || 'Unknown Emoji');
   }
   if (node.name === 'a') {
-    const href = decodeURIComponent(node.attribs.href);
+    const href = tryDecodeURIComponent(node.attribs.href);
     if (typeof href !== 'string') return undefined;
     if (testMatrixTo(href)) {
       const userMention = parseMatrixToUser(href);
diff --git a/src/app/components/url-preview/UrlPreviewCard.tsx b/src/app/components/url-preview/UrlPreviewCard.tsx
index fc9229fa..07c25f8a 100644
--- a/src/app/components/url-preview/UrlPreviewCard.tsx
+++ b/src/app/components/url-preview/UrlPreviewCard.tsx
@@ -9,6 +9,7 @@ import {
   useIntersectionObserver,
 } from '../../hooks/useIntersectionObserver';
 import * as css from './UrlPreviewCard.css';
+import { tryDecodeURIComponent } from '../../utils/dom';
 
 const linkStyles = { color: color.Success.Main };
 
@@ -43,7 +44,7 @@ export const UrlPreviewCard = as<'div', { url: string; ts: number }>(
               priority="300"
             >
               {typeof prev['og:site_name'] === 'string' && `${prev['og:site_name']} | `}
-              {decodeURIComponent(url)}
+              {tryDecodeURIComponent(url)}
             </Text>
             <Text truncate priority="400">
               <b>{prev['og:title']}</b>
diff --git a/src/app/pages/auth/AuthLayout.tsx b/src/app/pages/auth/AuthLayout.tsx
index 2ea94142..3943f42d 100644
--- a/src/app/pages/auth/AuthLayout.tsx
+++ b/src/app/pages/auth/AuthLayout.tsx
@@ -29,6 +29,7 @@ import { AutoDiscoveryInfoProvider } from '../../hooks/useAutoDiscoveryInfo';
 import { AuthFlowsLoader } from '../../components/AuthFlowsLoader';
 import { AuthFlowsProvider } from '../../hooks/useAuthFlows';
 import { AuthServerProvider } from '../../hooks/useAuthServer';
+import { tryDecodeURIComponent } from '../../utils/dom';
 
 const currentAuthPath = (pathname: string): string => {
   if (matchPath(LOGIN_PATH, pathname)) {
@@ -72,7 +73,7 @@ export function AuthLayout() {
   const clientConfig = useClientConfig();
 
   const defaultServer = clientDefaultServer(clientConfig);
-  let server: string = urlEncodedServer ? decodeURIComponent(urlEncodedServer) : defaultServer;
+  let server: string = urlEncodedServer ? tryDecodeURIComponent(urlEncodedServer) : defaultServer;
 
   if (!clientAllowedServer(clientConfig, server)) {
     server = defaultServer;
@@ -94,7 +95,7 @@ export function AuthLayout() {
 
   // if server is mismatches with path server, update path
   useEffect(() => {
-    if (!urlEncodedServer || decodeURIComponent(urlEncodedServer) !== server) {
+    if (!urlEncodedServer || tryDecodeURIComponent(urlEncodedServer) !== server) {
       navigate(
         generatePath(currentAuthPath(location.pathname), {
           server: encodeURIComponent(server),
diff --git a/src/app/plugins/react-custom-html-parser.tsx b/src/app/plugins/react-custom-html-parser.tsx
index 16704374..95e2f334 100644
--- a/src/app/plugins/react-custom-html-parser.tsx
+++ b/src/app/plugins/react-custom-html-parser.tsx
@@ -26,6 +26,7 @@ import {
   testMatrixTo,
 } from './matrix-to';
 import { onEnterOrSpace } from '../utils/keyboard';
+import { tryDecodeURIComponent } from '../utils/dom';
 
 const ReactPrism = lazy(() => import('./react-prism/ReactPrism'));
 
@@ -134,8 +135,8 @@ export const factoryRenderLinkifyWithMention = (
     attributes,
     content,
   }) => {
-    if (tagName === 'a' && testMatrixTo(decodeURIComponent(attributes.href))) {
-      const mention = mentionRender(decodeURIComponent(attributes.href));
+    if (tagName === 'a' && testMatrixTo(tryDecodeURIComponent(attributes.href))) {
+      const mention = mentionRender(tryDecodeURIComponent(attributes.href));
       if (mention) return mention;
     }
 
@@ -325,11 +326,11 @@ export const getReactCustomHtmlParser = (
           }
         }
 
-        if (name === 'a' && testMatrixTo(decodeURIComponent(props.href))) {
+        if (name === 'a' && testMatrixTo(tryDecodeURIComponent(props.href))) {
           const mention = renderMatrixMention(
             mx,
             roomId,
-            decodeURIComponent(props.href),
+            tryDecodeURIComponent(props.href),
             makeMentionCustomProps(params.handleMentionClick)
           );
           if (mention) return mention;
diff --git a/src/app/utils/dom.ts b/src/app/utils/dom.ts
index 1aea6754..ab4b8e65 100644
--- a/src/app/utils/dom.ts
+++ b/src/app/utils/dom.ts
@@ -196,3 +196,11 @@ export const setFavicon = (url: string): void => {
   if (!favicon) return;
   favicon.setAttribute('href', url);
 };
+
+export const tryDecodeURIComponent = (encodedURIComponent: string): string => {
+  try {
+    return decodeURIComponent(encodedURIComponent);
+  } catch {
+    return encodedURIComponent;
+  }
+};