#21883: fix: guard against undefined snapshot.skills in applySkillEnvOverride…
agents
size: XS
Cluster:
Skill and Session Management Fixes
Title: fix: guard against undefined snapshot.skills in applySkillEnvOverridesFromSnapshot
snapshot.skills can be undefined when a session is reset during an API rate-limit cooldown, causing a TypeError crash that compounds the original rate-limit issue.
Use nullish coalescing (snapshot.skills ?? []) to safely skip iteration when skills is not populated.
Summary
• Problem: applySkillEnvOverridesFromSnapshot crashes with TypeError: snapshot.skills is not iterable when snapshot exists but .skills is undefined
• Why it matters: During API rate-limit cooldowns, incomplete snapshots cause cascading crashes that prevent session recovery
• What changed: Added nullish coalescing (?? []) to the for...of loop on snapshot.skills
• What did NOT change (scope boundary): No changes to snapshot creation logic, skill resolution, or any other iteration over snapshot.skills elsewhere
Change Type (select all)
• [x] Bug fix
Scope (select all touched areas)
• [x] Skills / tool execution
Linked Issue/PR
• None (discovered via production logs)
User-visible / Behavior Changes
None. Previously crashed; now silently skips skill env overrides when skills data is unavailable.
Security Impact (required)
• New permissions/capabilities? No
• Secrets/tokens handling changed? No
• New/changed network calls? No
• Command/tool execution surface changed? No
• Data access scope changed? No
Repro + Verification
Environment
• OS: Ubuntu 22.04 (Linux 6.8.0-100-generic x64)
• Runtime/container: Node v22.22.0
• Model/provider: anthropic/claude-opus-4-6
• Integration/channel: Telegram
• Relevant config: Default OpenClaw gateway config
Steps
1. Trigger API rate-limit cooldown on all providers (heavy usage or 429 responses)
2. Run /new or /reset to start a new session while providers are in cooldown
3. Snapshot is created without .skills property populated
4. applySkillEnvOverridesFromSnapshot crashes on for...of snapshot.skills
Expected
• Session resets gracefully, skill env overrides are skipped if unavailable
Actual
• TypeError: snapshot.skills is not iterable — session fails to initialize, compounding rate-limit recovery
Evidence
Production log from 2026-02-20T05:20:21.021Z:
lane task error: lane=main durationMs=128 error="TypeError: snapshot.skills is not iterable"
lane task error: lane=session:agent:main:main durationMs=135 error="TypeError: snapshot.skills is not iterable"
Human Verification (required)
• Verified scenarios: Confirmed the crash in production logs, verified the fix changes only the iteration guard
• Edge cases checked: snapshot.skills being undefined, null, or empty array — all handled by ?? []
• What you did not verify: Could not reproduce rate-limit cooldown in test environment
Compatibility / Migration
• Backward compatible? Yes
• Config/env changes? No
• Migration needed? No
Failure Recovery (if this breaks)
• How to disable/revert this change quickly: Revert single line in src/agents/skills/env-overrides.ts
• Files/config to restore: src/agents/skills/env-overrides.ts
• Known bad symptoms reviewers should watch for: Skill env overrides silently not being applied (unlikely — only triggers when skills is already undefined)
Risks and Mitigations
• Risk: Masking a deeper issue where snapshot.skills should always be defined
• Mitigation: This is a defensive guard only; the root cause (incomplete snapshot during rate-limit) should be investigated separately
<!-- greptile_comment -->
<h3>Greptile Summary</h3>
Added nullish coalescing operator (`?? []`) to safely handle `undefined` `snapshot.skills` during session reset, preventing `TypeError: snapshot.skills is not iterable` crash during API rate-limit cooldowns.
- The fix is minimal and defensive, only affecting the iteration guard in `applySkillEnvOverridesFromSnapshot`
- Type signature correctly defines `skills` as required in `SkillSnapshot`, but runtime scenarios (deserialization, partial state during cooldowns) can produce incomplete snapshots
- No other code locations iterate over `snapshot.skills` without first checking for the snapshot itself being undefined
<h3>Confidence Score: 5/5</h3>
- Safe to merge with no risk
- Single-line defensive fix using idiomatic TypeScript nullish coalescing, matches existing pattern in codebase (line 69 checks `!snapshot`), addresses production crash with no side effects, properly handles edge cases (undefined, null, empty array)
- No files require special attention
<sub>Last reviewed commit: 20da030</sub>
<!-- greptile_other_comments_section -->
<sub>(2/5) Greptile learns from your feedback when you react with thumbs up/down!</sub>
<!-- /greptile_comment -->
Most Similar PRs
#16654: fix: refresh skills snapshot when managed skills change
by PhineasFleabottom · 2026-02-15
82.3%
#9221: fix(skills): use skillKey for env config lookup in snapshots
by gavinbmoore · 2026-02-05
81.9%
#22525: [Bug]: Session snapshot not reloading skills after gateway restart ...
by zwffff · 2026-02-21
81.6%
#22568: fix(gateway): bump skills snapshot version on startup so sessions r...
by zwffff · 2026-02-21
81.4%
#20533: fix: strip resolvedSkills from session store to prevent snapshot bloat
by echoVic · 2026-02-19
80.9%
#12209: fix(skills): refresh stale skill snapshot after gateway restart
by mcaxtr · 2026-02-09
80.4%
#11250: fix: expand skills watcher ignore list and improve session repair l...
by zhangzhefang-github · 2026-02-07
77.5%
#12956: fix: guard .trim() calls on potentially undefined workspaceDir
by omair445 · 2026-02-10
76.8%
#14023: fix: filter skills watcher to relevant file types to prevent FD exh...
by funmerlin · 2026-02-11
76.3%
#8150: fix(skills): block dangerous environment variables from skill config
by yubrew · 2026-02-03
76.3%