Skip to content

Crash importing a character with a minion main skill: ipairs(nil) in RefreshSkillSelectControls (Build.lua:2044) #2243

@HivemindMinion

Description

@HivemindMinion

Description

Importing a character whose main/displayed skill is a minion skill (e.g. Summon Infernal Hound) via Character Import crashes Path of Building once the passive tree is brought in. The error is a nil access in RefreshSkillSelectControls.

Error

In 'OnFrame': Modules/Build.lua:2044: bad argument #1 to 'ipairs' (table expected, got nil)
stack traceback:
	[C]: in function 'ipairs'
	Modules/Build.lua:2044: in function 'RefreshSkillSelectControls'
	Modules/Build.lua:1344: in function 'CallMode'
	Modules/Main.lua:372: in function <Modules/Main.lua:342>
	[C]: in function 'PCall'
	Launch.lua:112: in function 'OnFrame'

Steps to reproduce

The key condition is that the currently displayed main skill is a minion-summon (e.g. Summon Infernal Hound) at the moment a passive tree is imported.

  1. Have a build whose main displayed skill is a minion-summon (Summon Infernal Hound / a Skeletal minion). Easiest: import a minion character's Items & Skills, then set that minion summon as the main skill (or open an existing minion build).
  2. Import/Export Build → Character Import → Passive Tree and Jewels (or otherwise import/replace the passive tree).
  3. On the next frame, RefreshSkillSelectControls runs for the minion main skill before the minion's activeSkillList has been rebuilt → crash.

Notes from investigation:

  • It does not crash when the displayed main skill is a non-summon (an attack/spell skill, or a trigger like Cast on Minion Death) — the crashing branch (if activeSkill.minion then) only runs for skills that summon a minion.
  • A fresh character import sometimes auto-selects a non-summon group as the main skill, in which case it won't crash; it reliably crashes when the minion-summon is the displayed main skill during the tree import.

Workaround for users: import the Passive Tree first (before any minion-summon is the main skill), then Items and Skills.

Root cause

Modules/Build.lua, RefreshSkillSelectControls:

2043    if activeSkill.minion then
2044        for _, minionSkill in ipairs(activeSkill.minion.activeSkillList) do
...
2051        for _, statSet in ipairs(activeSkill.minion.activeSkillList[controls.mainSkillMinionSkill.selIndex]...) do

The code guards on activeSkill.minion being truthy, but then assumes activeSkill.minion.activeSkillList is a table. During the import transition the minion object exists but its activeSkillList has not yet been (re)built by a calculation pass, so it is nil when RefreshSkillSelectControls runs on the next frame — ipairs(nil) throws.

Suggested fix

Guard the inner access (both line 2044 and the dependent line 2051):

if activeSkill.minion and activeSkill.minion.activeSkillList then
    for _, minionSkill in ipairs(activeSkill.minion.activeSkillList) do
    ...
end

i.e. fall through to the else "" branch when the minion's skill list isn't ready, rather than dereferencing it.

Version

Reproduced on the latest dev (commit a82a33b), reported PoB version 0.20.0. Confirmed the unguarded access is still present in current dev.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions