Quick answer: Burst rejects managed types and ambiguous parallel writes. Mark read-only NativeArrays with [ReadOnly], write only to the index passed to Execute, and avoid string, List<T>, and references to MonoBehaviours inside job structs.

Here is how to fix Unity IJobParallelFor structs that produce Burst compile errors. You define a job, schedule it, and the console fills with red: BC1042: The managed function pointer cannot be used in Burst or error MJ0006: Cannot access NativeArray in parallel for loop. The fix is almost always one of two things: managed type leakage, or missing ReadOnly/WriteOnly attributes.

The Symptom

Compile errors only when Burst is enabled. With Burst disabled, the job runs slowly but correctly. With Burst on, the console emits BC* (Burst Compile) errors mentioning function pointers, managed methods, or boxed values. Or you hit safety errors at scheduling time accusing the job of unsafe parallel access.

What Causes This

Managed types in the job struct. Burst compiles to native code. It cannot use the managed runtime: no string, no class instances, no delegates that capture managed state, no List<T> or Dictionary<K,V>.

Calls to UnityEngine APIs. Debug.Log, Mathf.Sin, Vector3.Distance, and most UnityEngine namespace functions are not Burst-compatible. Use Unity.Mathematics equivalents (math.sin, math.distance, float3).

Multiple writes to a parallel-for array. IJobParallelFor allows writes only to the index passed to Execute(int index). Writing to other indices is a data race; Burst’s safety system rejects the schedule.

Read-only array without attribute. If you read but never write to a NativeArray, mark it [ReadOnly]. Without it, Burst assumes you might write, which prevents safe parallel reads in some cases and pollutes profiler attributions.

The Fix

Step 1: Use Unity.Mathematics types.

using Unity.Burst;
using Unity.Collections;
using Unity.Jobs;
using Unity.Mathematics;

[BurstCompile]
public struct MoveJob : IJobParallelFor
{
    [ReadOnly]  public NativeArray<float3> velocities;
                public NativeArray<float3> positions;
    [ReadOnly]  public float deltaTime;

    public void Execute(int index)
    {
        positions[index] += velocities[index] * deltaTime;
    }
}

Step 2: Schedule with the right batch size.

var job = new MoveJob {
    velocities = velocityArray,
    positions = positionArray,
    deltaTime = Time.deltaTime,
};

JobHandle handle = job.Schedule(positionArray.Length, 64);
handle.Complete();

Batch size 64 is a sensible default. For very small jobs, use a higher batch size (256+) so the scheduling overhead does not dominate.

Step 3: Avoid managed APIs.

// BAD: Mathf in a Burst job
float distance = Mathf.Sqrt(dx*dx + dy*dy);

// GOOD: Unity.Mathematics
float distance = math.sqrt(dx*dx + dy*dy);

// BAD: Debug.Log inside Execute
Debug.Log("value");

// GOOD: Use Unity Logging or Burst-compatible logging only

Step 4: Use NativeDisableParallelForRestriction sparingly. If you know writes are safe (e.g., you spread workload by chunks), disable the restriction:

[NativeDisableParallelForRestriction]
public NativeArray<float> output;

Use only when you can prove no two threads write the same index. Otherwise data corruption is silent and platform-dependent.

Step 5: Inspect the Burst Inspector. Window → Analysis → Burst Inspector. Pick your job from the list. The right pane shows the assembly Burst produced (or a red error message). Errors here pinpoint the offending line, often a single managed call buried in a helper struct.

Common Burst Errors Cheat Sheet

BC1042: managed function pointer
       Cause:  delegate, virtual call, or interface dispatch
       Fix:    use FunctionPointer<T> or refactor to direct call

BC1059: managed method invocation
       Cause:  string, List, Mathf, Debug
       Fix:    replace with Unity.Mathematics / NativeArray

MJ0006: NativeArray in parallel-for
       Cause:  writing to index other than Execute’s index
       Fix:    add ReadOnly, or NativeDisableParallelForRestriction

Performance Note

Burst-compiled IJobParallelFor with batch size 64 typically runs 5–20x faster than equivalent main-thread code. The perf win disappears entirely if jobs have to wait on managed sync points. Schedule jobs early in the frame, complete late, and chain dependencies via JobHandle.CombineDependencies.

“Burst speaks native, not managed. ReadOnly, WriteOnly, and Unity.Mathematics are the three keys to compile success.”

Related Issues

For DOTS issues with Burst, see DOTS Burst Managed Code Error. For Burst silently skipping jobs, see Burst Silently Skipping Job.

No managed types. ReadOnly attributes. Index-local writes. Burst is fast and strict.