Fix panic when opening an invalid URL (#42483)

Richard Feldman created

Now instead of a panic we see this:

<img width="511" height="132" alt="Screenshot 2025-11-11 at 3 47 25 PM"
src="https://github.com/user-attachments/assets/48ba2f41-c5c0-4030-9331-0d3acfbf9461"
/>


Release Notes:

- Trying to open invalid URLs in a browser now shows an error instead of
panicking

Change summary

crates/gpui/src/platform/mac/platform.rs |  9 ++++++---
crates/zed/src/zed.rs                    | 19 ++++++++++++++++++-
2 files changed, 24 insertions(+), 4 deletions(-)

Detailed changes

crates/gpui/src/platform/mac/platform.rs 🔗

@@ -651,9 +651,12 @@ impl Platform for MacPlatform {
 
     fn open_url(&self, url: &str) {
         unsafe {
-            let url = NSURL::alloc(nil)
-                .initWithString_(ns_string(url))
-                .autorelease();
+            let ns_url = NSURL::alloc(nil).initWithString_(ns_string(url));
+            if ns_url.is_null() {
+                log::error!("Failed to create NSURL from string: {}", url);
+                return;
+            }
+            let url = ns_url.autorelease();
             let workspace: id = msg_send![class!(NSWorkspace), sharedWorkspace];
             msg_send![workspace, openURL: url]
         }

crates/zed/src/zed.rs 🔗

@@ -726,7 +726,24 @@ fn register_actions(
                 ..Default::default()
             })
         })
-        .register_action(|_, action: &OpenBrowser, _window, cx| cx.open_url(&action.url))
+        .register_action(|workspace, action: &OpenBrowser, _window, cx| {
+            // Parse and validate the URL to ensure it's properly formatted
+            match url::Url::parse(&action.url) {
+                Ok(parsed_url) => {
+                    // Use the parsed URL's string representation which is properly escaped
+                    cx.open_url(parsed_url.as_str());
+                }
+                Err(e) => {
+                    workspace.show_error(
+                        &anyhow::anyhow!(
+                            "Opening this URL in a browser failed because the URL is invalid: {}\n\nError was: {e}",
+                            action.url
+                        ),
+                        cx,
+                    );
+                }
+            }
+        })
         .register_action(|workspace, _: &workspace::Open, window, cx| {
             telemetry::event!("Project Opened");
             let paths = workspace.prompt_for_open_path(