Unroller AccessViolationException in Rhino.Compute

Hey everyone.

I’m currently running in a problem with rhino.compute and the unroller. In my rhino.compute config i set CreateHeadlessDoc = false.

The code is basically that…

  var unroller = new Unroller(brep)
      {
          ExplodeOutput = false,
          AbsoluteTolerance = 0.1
      };

  var res = unroller.PerformUnroll(out var c, out var up,  out var ud);

What I’m getting when running it in rhino.compute is:


Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Repeat 2 times:

at UnsafeNativeMethods.CRhinoUnroll_CreateFlatBreps(IntPtr, Double, Int32 ByRef, Int32 ByRef, Int32 ByRef, Int32 ByRef)


I’m not using the doc tolerances to not access the not available doc.

When I use CreateHeadlessDoc = true it works without a problem.

My question would be:

  1. Is that a bug, or is the unroller not compatible with a headless env?
  2. What are the implications when I activate CreateHeadlessDoc = true in rhino.compute / are there any downsides?

If I remember correctly, it worked previous v8.20 I’m now on version Rhino 8 SR25 2025-11-24 (Rhino 8, 8.25.25328.11001)

Best and thank you already in advance

I have the same exact problem with the same crash call stack but unfortunately –create-headless-doc true doesn’t make a difference. I’m using Version 8 SR30
(8.30.26103.11001, 2026-04-13)

I also have simple repro that may help.
I created simple gh file that reference Unroll component and executed it on the server using hops. I got the errors below.

Also found these errors from log-compute-geometry.txt from the server
CG [16:14:36 ERR] An exception occurred while processing request
System.Exception: GH - Missing Definition Objects

Some context, I’m calling the compute server through custom endpoints. I debugged the geometry.compute.exe and found out why the –create-headless-doc true param has no effect. The reason as follows: In GeometryEndPoint.Post(…), there is no reference to Config.CreateHeadlessDoc in contrast to ResthopperEndpointsModule.GrasshopperSolveHelper(..).

So what I did is create headless doc if Config.CreateHeadlessDoc == true . Now, I’m able to call the unroller on compute if –create-headless-doc true .

The whole method for reference

`public async Task Post(HttpContext context)
{
    context.Response.ContentType = "application/json";
    DateTime start = DateTime.Now;
    StopAt stopat = StopAt.None;
    bool multiple = false;
    Dictionary<string, string> returnModifiers = null;

    Rhino.RhinoDoc createdDoc = null;

    try
    {
        if (Config.CreateHeadlessDoc)
        {
            createdDoc = Rhino.RhinoDoc.CreateHeadless(null);
            Rhino.RhinoDoc.ActiveDoc = createdDoc;
        }

        foreach (string name in context.Request.Query.Keys)
        {
            if (name.StartsWith("return.", StringComparison.InvariantCultureIgnoreCase))
            {
                if (returnModifiers == null)
                    returnModifiers = new Dictionary<string, string>();
                string dataType = "Rhino.Geometry." + name.Substring("return.".Length);
                string items = context.Request.Query[name];
                returnModifiers[dataType] = items;
                continue;
            }
            if (name.Equals("multiple", StringComparison.InvariantCultureIgnoreCase))
            {
                multiple = bool.Parse(context.Request.Query[name][0]);
                continue;
            }
            if (name.Equals("stopat", StringComparison.InvariantCultureIgnoreCase))
            {
                int val = int.Parse(context.Request.Query[name][0]);
                stopat = (StopAt)val;
            }
        }
        if (StopAt.PostStart == stopat)
        {
            await context.Response.WriteAsync($"{(DateTime.Now - start).TotalSeconds}");
            return;
        }

        var jsonString = await new System.IO.StreamReader(context.Request.Body).ReadToEndAsync();
        if (StopAt.BodyToString == stopat)
        {
            await context.Response.WriteAsync($"{(DateTime.Now - start).TotalSeconds}");
            return;
        }

        object data = string.IsNullOrWhiteSpace(jsonString) ? null : JsonConvert.DeserializeObject(jsonString);
        var ja = data as Newtonsoft.Json.Linq.JArray;
        string resultString = null;
        if (multiple && ja.Count > 1)
        {
            var result = new System.Text.StringBuilder("[");
            for (int i = 0; i < ja.Count; i++)
            {
                if (i > 0)
                    result.Append(",");
                var item = ja[i] as Newtonsoft.Json.Linq.JArray;
                result.Append(HandlePostHelper(item, returnModifiers));
            }
            result.Append("]");
            resultString = result.ToString();
        }
        else
            resultString = HandlePostHelper(ja, returnModifiers);

        if (StopAt.CalculationsComplete == stopat)
        {
            await context.Response.WriteAsync($"{(DateTime.Now - start).TotalSeconds}");
            return;
        }
        await context.Response.WriteAsync(resultString);
    }
    finally
    {
        if (createdDoc != null)
        {
            createdDoc.Dispose();
        }
    }
}`

Have you tried to set an environment variable like this:

RHINO_COMPUTE_CREATE_HEADLESS_DOC=true

So instead of putting it in the compute project, use it in a ENV var.

But as you stated, if that’s the case, ResthopperEndpointsModule.GrasshopperSolveHelper(..) would also not do it.

Yes. It won’t make a diff as there is no mention whatsoever to the headless doc in this code path GeometryEndPoint.Post(…)

I think the reason the -create-headless-doc true isn’t working is because you’re missing an extra hyphen. You need the pass the arguments as --create-headless-doc true in your web.config or startup arguments for it to work properly.

Can you attach this definition here so I can test this on my end?

Thanks for the reply but unfortunately it’s not the case. The missing hyphen is just the forum post editor.

It’s exactly the same as in the above screenshot. However, I’m attaching the gh file here for convenience. You just need to wrap it in Hops component.

context_unroll.zip (6.6 KB)

@Mostafa this file is using an Unroll component built by a 3rd party developer. Scrolling up to one of your previous posts, you posted a snippet of the console output on your VM:

CG [16:14:36 ERR] An exception occurred while processing request System.Exception: GH - Missing Definition Objects

This tells me that you have not installed the OpenNest plugin on your VM. So when you go and try to perform a solve on your VM, it can’t find the GHA which contains the unroll component and the solve fails. You can send an HTTP request to your VM at the endpoint /plugins/gh/installed and it should send you back a JSON response of all of the installed GH plugins that are currently installed on that machine.

I think you need to log into your VM as your RhinoComputeUser account and install OpenNest and then restart your server.

Thanks @AndyPayne for the investigation. It’s my fault. I didn’t realize it’s part of OpenNest package and not Grasshopper built-in package. So, that means this repro is invalid.

Now, let’s go back to the original problem. I’ve custom endpoint which calls unroller.PerformUnroll() on the server which fails with the exact error in the first post.

Important Note: The endpoint is not called through grasshopper. It’s called through a Rhino command.

Fatal error. System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt.
Repeat 2 times:

at UnsafeNativeMethods.CRhinoUnroll_CreateFlatBreps(IntPtr, Double, Int32 ByRef, Int32 ByRef, Int32 ByRef, Int32 ByRef)

setting -–create-headless-doc true in web.config doesn’t make a difference unless I modify compute source code and build from sources as shown in my previous reply.

Anyway, relying on setting -–create-headless-doc true in order to make the unroller work is an obvious bug in the unroller.

I appreciate your help.