Issue writing to Dynamic Buffer from Job

I’m getting an error trying to write to an entity’s dynamicBuffer from within an IJob : “InvalidOperationException: The native container has been declared as [ReadOnly] in the job, but you are writing to it.”
I’m confused, I don’t think I’m declaring it as readonly.

This is the offending line :
woodCutterBuffer.Add(new WoodCutterBufferElement { Value = woodCutterEntity });

public struct ProcessUnAssignedWoodCutters : IJob
        {
            [ReadOnly]
            [DeallocateOnJobCompletion]
            public NativeArray<ArchetypeChunk> unAssignedWoodCutters;
           
            [DeallocateOnJobCompletion]
            public NativeArray<ArchetypeChunk> woodCutterBuildingChunks;

            public ArchetypeChunkBufferType<WoodCutterBufferElement> woodCutterBufferType;
           
            public ArchetypeChunkComponentType<WoodCutterBuilding> woodCutterBuildingType;
           
            [ReadOnly]
            public ArchetypeChunkEntityType entityType;

            public EntityCommandBuffer buffer;

            public void Execute()
            {
                for (var i = 0; i < unAssignedWoodCutters.Length; i++)
                {
                    var chunk = unAssignedWoodCutters[i];
                    var chunkCount = chunk.Count;
                    var woodCutterEntities = chunk.GetNativeArray(entityType);

                    for (var j = 0; j < chunkCount; j++)
                    {
                        var woodCutterEntity = woodCutterEntities[j];

                        for (var x = 0; x < woodCutterBuildingChunks.Length; x++)
                        {
                            var buildingChunk = woodCutterBuildingChunks[x];
                            var buildingChunkCount = buildingChunk.Count;
                            var buildingWoodCutterBuffers = buildingChunk.GetBufferAccessor(woodCutterBufferType);
                            var buildingDataArray = buildingChunk.GetNativeArray(woodCutterBuildingType);

                            for (var y = 0; y < buildingWoodCutterBuffers.Length; y++)
                            {
                                var woodCutterBuffer = buildingWoodCutterBuffers[y];
                                var buildingData = buildingDataArray[y];
                                if (woodCutterBuffer.Length == buildingData.maxWorkers)
                                {
                                    continue;
                                }

                                woodCutterBuffer.Add(new WoodCutterBufferElement { Value = woodCutterEntity });
                                buffer.RemoveComponent(woodCutterEntity, typeof(NotAssignedToBuilding));
                            }
                        }
                    }
                }
            }
        }



private JobHandle ScheduleUnAssignedWorkersJob(JobHandle inputDeps)
        {
            var entityType = EntityManager.GetArchetypeChunkEntityType();
           
            // process un-assigned woodcutters
            var unassignedWoodCuttersQuery = new EntityArchetypeQuery
            {
                Any = new ComponentType[0],
                None = new ComponentType[0],
                All = new ComponentType[] { typeof(WoodCutterOccupation), typeof(NotAssignedToBuilding) }
            };

            var woodCutterBuildingQuery = new EntityArchetypeQuery
            {
                Any = new ComponentType[0],
                None = new ComponentType[0],
                All = new ComponentType[] { typeof(WoodCutterBuilding) }
            };

            woodCutterBuildingChunks = EntityManager.CreateArchetypeChunkArray(woodCutterBuildingQuery, Allocator.TempJob);
            unassignedWoodCutterChunks = EntityManager.CreateArchetypeChunkArray(unassignedWoodCuttersQuery, Allocator.TempJob);
            var woodCutterBuildingBufferType = EntityManager.GetArchetypeChunkBufferType<WoodCutterBufferElement>(false);
            var woodCutterBuildingType = EntityManager.GetArchetypeChunkComponentType<WoodCutterBuilding>(false);

            var processUnAssignedWoodCuttersJob = new ProcessUnAssignedWoodCutters
            {
                unAssignedWoodCutters = unassignedWoodCutterChunks,
                woodCutterBuildingChunks = woodCutterBuildingChunks,
                woodCutterBufferType = woodCutterBuildingBufferType,
                woodCutterBuildingType = woodCutterBuildingType,
                buffer = unassignedWorkersBarrier.CreateCommandBuffer(),
                entityType = entityType
            };

            return processUnAssignedWoodCuttersJob.Schedule(inputDeps);
        }



[InternalBufferCapacity(8)]
    public struct WoodCutterBufferElement : IBufferElementData
    {
        // These implicit conversions are optional, but can help reduce typing.
        public static implicit operator Entity(WoodCutterBufferElement e) { return e.Value; }
        public static implicit operator WoodCutterBufferElement(Entity e) { return new WoodCutterBufferElement { Value = e }; }

        // Actual value each buffer element will store.
        public Entity Value;
    }

hmm… if you’re calling this within a component system, you shouldn’t be using the EntityManager.Get/CreateArchetypeChunk… types, you should be using the [Job]ComponentSystem variants. This may be what’s causing your issue.

What are the [Job]ComponentSystem variants ?

Posted the same thing here: (BUG) BufferArray safety breaks when used differently in multiple systems

Seems to be an issue when declared readonly in one system and writeable in another.

If the readonly job occurs before the write job the error will throw.
If it occurs the other way it’ll work fine.

As a workaround, either order your systems by ones that do writing ones first or call Complete() on the handle before the write jobs.