Startup completes as expected on WSL Unbuntu 24.04, logs and everything. But I’ve been playing in a new endpoint to see what’s safe to call and when. For example, the following three lines in a new /grasshopper endpoint:
``` var _ = Grasshopper.Instances.ActiveCanvas;
var doc = new Grasshopper.Kernel.GH_Document();
var server = Grasshopper.Instances.ComponentServer;
```
The first two complete without issue, but the last one throws:
terminate called after throwing an instance of ‘PAL_SEHException
The GrasshopperEndpoint file is commented out, is there somewhere else in the codebase I can spy on the right way to invoke a script? Tried a few dozen things I can also list out here later if helpful!
It looks like some of the standard components that are shipping with rhino on linux crash on some sort of load. I’ve had to disable Kangaroo and IOComponents, but now we’re moving again. More soon.
Thanks for being a guinea pig Chuck. There are still a number of low level C++ operations that are “unimplemented” and throw exceptions. If we can repeat the problems you are seeing there’s a good chance it is because of some unimplemented code that we can focus on and get added to the build.
To piggyback on this, (thanks Chuck, that fix worked for one step) the next blocker I’ve found:
Grasshopper.Instances.InvalidateCanvas gets called by GH_Document.NewSolution
This throws because that brings in System.Drawing which kills the whole deal.
I know McNeel build their own version of Drawing (but compute seems to pull in the microsoft package?)
Stack Trace
[00:27:41 INF] Starting compute.geometry instance on port 6003
CG [00:27:41 INF] Child process started at 03/25/2026 00:27:41
CG [00:27:41 INF] Compute 9.0.0.0, Rhino 9.0.26083.1000
RC [00:27:41 INF] Starting compute.geometry instance on port 6004
CG [00:27:41 INF] Child process started at 03/25/2026 00:27:41
CG [00:27:41 INF] Compute 9.0.0.0, Rhino 9.0.26083.1000
CG [00:27:41 INF] Child process started at 03/25/2026 00:27:41
CG [00:27:41 INF] Compute 9.0.0.0, Rhino 9.0.26083.1000
CG [00:27:43 INF] Skipping DocumentServer.AddDocument on Linux headless compute
CG [00:27:43 ERR] Connection id "0HNKA0L9N9GMI", Request id "0HNKA0L9N9GMI:00000001": An unhandled exception was thrown by the application.
System.TypeInitializationException: The type initializer for 'Grasshopper.GUI.Canvas.GH_Canvas' threw an exception.
---> System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation.
---> System.PlatformNotSupportedException: System.Drawing.Common is not supported on this platform.
at System.Drawing.Image..ctor()
at System.Drawing.Bitmap..ctor(Stream stream)
at System.RuntimeMethodHandle.InvokeMethod(Object target, Void** arguments, Signature sig, Boolean isConstructor)
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
--- End of inner exception stack trace ---
at System.Reflection.MethodBaseInvoker.InvokeDirectByRefWithFewArgs(Object obj, Span`1 copyOfArgs, BindingFlags invokeAttr)
at System.Reflection.MethodBaseInvoker.InvokeWithOneArg(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture)
at System.Resources.Extensions.DeserializingResourceReader.DeserializeObject(Int32 typeIndex)
at System.Resources.Extensions.DeserializingResourceReader._LoadObjectV2(Int32 pos, ResourceTypeCode& typeCode)
at System.Resources.Extensions.DeserializingResourceReader.LoadObjectV2(Int32 pos, ResourceTypeCode& typeCode)
at System.Resources.Extensions.DeserializingResourceReader.LoadObject(Int32 pos, ResourceTypeCode& typeCode)
at System.Resources.Extensions.RuntimeResourceSet.ReadValue(DeserializingResourceReader reader, Int32 dataPos, Boolean isString, ResourceLocator& locator)
at System.Resources.Extensions.RuntimeResourceSet.GetObject(String key, Boolean ignoreCase, Boolean isString)
at System.Resources.Extensions.RuntimeResourceSet.GetObject(String key, Boolean ignoreCase)
at System.Resources.ResourceManager.GetObject(String name, CultureInfo culture, Boolean wrapUnmanagedMemStream)
at Grasshopper.My.Resources.Res_GUI.get_Doc_Aborted_48x48() in /scratch/buildAgent/work/db0f3a602490518c/src4/rhino4/Plug-ins/Grasshopper/Grasshopper/Res_GUI.Designer.vb:line 292
at Grasshopper.GUI.Canvas.GH_Canvas..cctor() in /scratch/buildAgent/work/db0f3a602490518c/src4/rhino4/Plug-ins/Grasshopper/Grasshopper/GH_Canvas.vb:line 3458
--- End of inner exception stack trace ---
at Grasshopper.GUI.Canvas.GH_Canvas.get_Canvases() in /scratch/buildAgent/work/db0f3a602490518c/src4/rhino4/Plug-ins/Grasshopper/Grasshopper/GH_Canvas.vb:line 129
at Grasshopper.Instances.InvalidateCanvas() in /scratch/buildAgent/work/db0f3a602490518c/src4/rhino4/Plug-ins/Grasshopper/Grasshopper/Instances.vb:line 507
at Grasshopper.Kernel.GH_Document.NewSolution(Boolean expireAllObjects, GH_SolutionMode mode) in /scratch/buildAgent/work/db0f3a602490518c/src4/rhino4/Plug-ins/Grasshopper/Grasshopper/GH_DocumentSolutionMethods.vb:line 311
at compute.geometry.GrasshopperDefinition.Solve(Int32 rhinoVersion, SchemaDataFormat format)
at compute.geometry.ResthopperEndpointsModule.GrasshopperSolveHelper(Schema input, String body, Stopwatch stopwatch, HttpContext ctx)
at compute.geometry.ResthopperEndpointsModule.Grasshopper(HttpContext ctx)
at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol.ProcessRequests[TContext](IHttpApplication`1 application)
RC [00:27:43 ERR] HTTP POST /grasshopper responded 500 in 2919.6371 ms
@chris.welch I’m having some success with ScheduleSolution(0) instead of NewSolution() ! But still getting a sense for what might be quietly different.
Edit: Spoke too soon. I don’t think this is working the way I first thought it was.
Coming up a bit dry on alternatives (we are now attempting reflection ) so would like to +1 Chris:
Ideally, a way to make GH_Document.NewSolution safe to call on Linux
Alternatively, some details on how to use ScheduleSolution(0) on Linux, if possible. (I can’t get any document solution events to fire, but am totally guessing at how this is supposed to work.)
Yeah, I’m calling GH blocked for now until there’s a fix for this custom System.Drawing that McNeel manage - @stevebaer, that’s over the fence to you guys I think. Very excited about this progress, but not enough to keep hacking around the edges
Managing to solve Grasshopper definitions on Linux (very cool). Sometimes certain components will hard crash the server (pain). It’s the same error we were reporting at the start of the thread: the kind of thing that hits some low level code and kills the process (even within a try/catch).
To help with debugging, I’ve forked and modified the rhino compute repo here:
It adds a /debug/:fileName endpoint to the compute.geometry project that will load and try to solve a small diagnostic grasshopper script. (GET http://localhost:7777/debug/000-control.gh should work). It also has a devcontainer there that replicates my WSL environment.
Please take a swing and let me know if it helps clarify the nature of the crashes at all! (And anything else I can add to help with testing.) I’ll keep dropping cases in there and reporting here.
tldr; it feels like any time a surface gets involved, things complain. The cases here are a simple extrusion or a circle, or passing it into the Boundary component.
@chris.welch It would be good to understand what you are trying to do. I worked with @Chuck_Driesler today to see what he was trying to set up. He was trying to run his own slightly modified version of Rhino.Compute, built from source. In this case, one needs to export the environment variables explicitly, for example, by adding them to ~/.profile and then running source ~./profile
The steps we took:
sudo nano ~/.profile
# add this to the bottom of the file
export RHINO_TOKEN=<your-token-here>
export RHINO_COMPUTE_CREATE_HEADLESS_DOC=true
# save and close the file
source ~./profile
# run dotnet run from the rhino.compute src directory
But that worked for his situation. It would be good to know a bit more about what you are doing to understand where things are going wrong.