English (short)
When an entity collides with an ElectricalProgressive block, DamageManager.DamageEntity throws KeyNotFoundException: The given key '0' was not present in the dictionary. Vintage Story surfaces this as Error while enumerating tickables from the physics thread. Short burst (8 errors in ≈4 seconds) with ≈2k tickables online — no server crash, but entity damage/collision handling fails for that interaction.
English — full issue body (copy to GitHub)
Title: DamageManager.DamageEntity: KeyNotFoundException for key 0 on entity collide (tickables / physics errors)
Labels (suggested): bug, core, basics, crash-adjacent, physics
Summary
BlockEBase.OnEntityCollide calls DamageManager.DamageEntity. Inside DamageManager (≈ line 220) code indexes a dictionary with key 0 (dict[0] / get_Item(0)) without a presence check. When that entry is missing, the exception escapes into the engine physics path and is reported as:
Error while enumerating tickables. Tickables total count is N
followed by the KeyNotFoundException.
Environment
| Component |
Version / note |
| Vintage Story |
1.22.3 (Stable), network 1.22.6, API 1.22.0 |
| electricalprogressivecore |
3.3.0 |
| electricalprogressivebasics |
3.3.1 |
| electricalprogressiveqol |
3.3.1 (loaded; not in this stack) |
| electricalprogressiveindustry |
0.7.0 |
| electricalprogressivetransport |
2.0.0 |
| OS / runtime |
Linux server (Ubuntu), .NET Server GC |
Steps to reproduce
Not fully isolated to a single block type in our logs, but the call path is deterministic:
- Have ElectricalProgressive blocks in the world that implement damage-on-collide via
BlockEBase.OnEntityCollide.
- Move a player/entity into collision with such a block while electrical parameters /
EParams state is incomplete or missing index 0.
- Observe
server-main.log for Error while enumerating tickables + KeyNotFoundException with the stack below.
On our server the burst coincided with a player (Useewa) reconnecting / moving near underground coordinates (HUD ≈ 689 … −1377, world ≈ 512682 5–8 510652), with corpse cleanup spam immediately before the errors. Exact block code at the collide site was not printed by the engine.
Expected
- Missing electrical parameter slot / dictionary key is treated as “no damage” or default params.
- Physics tick continues without an unhandled exception.
- At most one diagnostic warning if state is corrupt.
Actual
Exception on the physics worker; VS logs tickable enumeration errors. On 2026-08-08 we recorded 8 such errors between 18:35:57 and 18:36:01, with tickable counts rising ≈ 2084 → 2142. Server did not crash; activity resumed normally afterward.
Stack trace (representative)
[Error] Error while enumerating tickables. Tickables total count is 2084
[Error] Exception: The given key '0' was not present in the dictionary.
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at ElectricalProgressive.Utils.DamageManager.DamageEntity(
IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing,
EParams[] AllEparams, Block block, Single specifiedDamage)
in .../ElectricalProgressive-Core/Utils/DamageManager.cs:line 220
at ElectricalProgressive.Content.Block.BlockEBase.OnEntityCollide(
IWorldAccessor world, Entity entity, BlockPos pos, BlockFacing facing,
Vec3d collideSpeed, Boolean isImpact)
in .../ElectricalProgressive-Basics/Content/Block/BlockEBase.cs:line 65
at Vintagestory.API.MathTools.CollisionTester.ApplyTerrainCollision_Patch1(...)
at Vintagestory.GameContent.EntityBehaviorControlledPhysics.ApplyTests(...)
at Vintagestory.GameContent.EntityBehaviorControlledPhysics.OnPhysicsTick(Single dt)
at Vintagestory.Server.PhysicsManager.DoWork(Int32 threadNumber)
Root cause (mod-side)
In DamageManager.cs ≈ line 220, dictionary access assumes key 0 always exists (likely voltage tier, facing bucket, or EParams channel). For some placed blocks / unloaded BE state / partial AllEparams, that key is absent.
BlockEBase.OnEntityCollide (Basics, ≈ line 65) invokes damage without guarding against incomplete params.
Suggested fix
- Use
TryGetValue(0, out var …) (or ContainsKey) and fall back to a safe default / skip damage.
- Validate
AllEparams / block entity electrical state before indexing.
- Catch and log once per block position (rate-limited) instead of letting the exception reach
PhysicsManager.
- Add a regression test: entity collide with EP block that has empty/partial param dictionary.
Impact
- Severity: Medium (no hard crash observed; physics/damage path broken for the colliding entity; noisy errors; potential unfair damage skip or repeated fails while standing in the block).
- Can appear as random “tickables” errors when players walk into machines/cables.
Related context from our logs (same minute)
playercorpseforked destroyed/recreated corpses for the same player just before the burst.
- Player death a few minutes later was from a mob (bell-headed shivers), not necessarily from this exception.
- Not related to the separate EOven × XSkills
AmbiguousMatchException spam earlier the same day.
Русский (кратко)
При коллизии сущности с блоком ElectricalProgressive DamageManager.DamageEntity падает с KeyNotFoundException (ключ 0). Движок пишет Error while enumerating tickables. У нас — 8 ошибок за ≈4 секунды (18:35:57–18:36:01). Сервер жив, но обработка урона/физики в этом кадре ломается.
Русский — подробности
Заголовок: DamageManager.DamageEntity: нет ключа 0 в словаре при OnEntityCollide (ошибки tickables)
Цепочка
PhysicsManager → controlled physics → BlockEBase.OnEntityCollide (Basics ≈65) → DamageManager.DamageEntity (Core ≈220) → Dictionary[0] без проверки.
Окружение
- VS 1.22.3
- EP Core 3.3.0, Basics 3.3.1
Наблюдение (наш сервер, 2026-08-08)
- Время: 18:35:57–18:36:01
- 8 пар Error + Exception
Tickables total count ≈ 2084…2142 (это размер списка tickable’ов, не число багов)
Перед этим игрок Useewa перезаходил; около HUD ≈ 689 / −1377 шли сообщения playercorpseforked про труп. Точный код электроблока в лог не попал.
Ожидание
Нет ключа → нет урона / дефолтные параметры, без exception в physics thread.
Предлагаемый фикс
TryGetValue, валидация EParams, не пробрасывать исключение в PhysicsManager; один rate-limited warning при битом состоянии блока.
English (short)
When an entity collides with an ElectricalProgressive block,
DamageManager.DamageEntitythrowsKeyNotFoundException: The given key '0' was not present in the dictionary. Vintage Story surfaces this asError while enumerating tickablesfrom the physics thread. Short burst (8 errors in ≈4 seconds) with ≈2k tickables online — no server crash, but entity damage/collision handling fails for that interaction.English — full issue body (copy to GitHub)
Title:
DamageManager.DamageEntity:KeyNotFoundExceptionfor key0on entity collide (tickables / physics errors)Labels (suggested):
bug,core,basics,crash-adjacent,physicsSummary
BlockEBase.OnEntityCollidecallsDamageManager.DamageEntity. InsideDamageManager(≈ line 220) code indexes a dictionary with key0(dict[0]/get_Item(0)) without a presence check. When that entry is missing, the exception escapes into the engine physics path and is reported as:Error while enumerating tickables. Tickables total count is Nfollowed by the
KeyNotFoundException.Environment
Steps to reproduce
Not fully isolated to a single block type in our logs, but the call path is deterministic:
BlockEBase.OnEntityCollide.EParamsstate is incomplete or missing index0.server-main.logforError while enumerating tickables+KeyNotFoundExceptionwith the stack below.On our server the burst coincided with a player (
Useewa) reconnecting / moving near underground coordinates (HUD ≈689 … −1377, world ≈512682 5–8 510652), with corpse cleanup spam immediately before the errors. Exact block code at the collide site was not printed by the engine.Expected
Actual
Exception on the physics worker; VS logs tickable enumeration errors. On 2026-08-08 we recorded 8 such errors between 18:35:57 and 18:36:01, with tickable counts rising ≈ 2084 → 2142. Server did not crash; activity resumed normally afterward.
Stack trace (representative)
Root cause (mod-side)
In
DamageManager.cs≈ line 220, dictionary access assumes key0always exists (likely voltage tier, facing bucket, orEParamschannel). For some placed blocks / unloaded BE state / partialAllEparams, that key is absent.BlockEBase.OnEntityCollide(Basics, ≈ line 65) invokes damage without guarding against incomplete params.Suggested fix
TryGetValue(0, out var …)(orContainsKey) and fall back to a safe default / skip damage.AllEparams/ block entity electrical state before indexing.PhysicsManager.Impact
Related context from our logs (same minute)
playercorpseforkeddestroyed/recreated corpses for the same player just before the burst.AmbiguousMatchExceptionspam earlier the same day.Русский (кратко)
При коллизии сущности с блоком ElectricalProgressive
DamageManager.DamageEntityпадает сKeyNotFoundException(ключ0). Движок пишетError while enumerating tickables. У нас — 8 ошибок за ≈4 секунды (18:35:57–18:36:01). Сервер жив, но обработка урона/физики в этом кадре ломается.Русский — подробности
Заголовок:
DamageManager.DamageEntity: нет ключа0в словаре приOnEntityCollide(ошибки tickables)Цепочка
PhysicsManager→ controlled physics →BlockEBase.OnEntityCollide(Basics ≈65) →DamageManager.DamageEntity(Core ≈220) →Dictionary[0]без проверки.Окружение
Наблюдение (наш сервер, 2026-08-08)
Tickables total count≈ 2084…2142 (это размер списка tickable’ов, не число багов)Перед этим игрок Useewa перезаходил; около HUD ≈ 689 / −1377 шли сообщения
playercorpseforkedпро труп. Точный код электроблока в лог не попал.Ожидание
Нет ключа → нет урона / дефолтные параметры, без exception в physics thread.
Предлагаемый фикс
TryGetValue, валидацияEParams, не пробрасывать исключение вPhysicsManager; один rate-limited warning при битом состоянии блока.