Skip to content

fix(execution): null guard em getLastCheckpoint/getCheckpoint (#513)#523

Closed
nikolasdehor wants to merge 2 commits intoSynkraAI:mainfrom
nikolasdehor:fix/build-state-manager-checkpoint-guard
Closed

fix(execution): null guard em getLastCheckpoint/getCheckpoint (#513)#523
nikolasdehor wants to merge 2 commits intoSynkraAI:mainfrom
nikolasdehor:fix/build-state-manager-checkpoint-guard

Conversation

@nikolasdehor
Copy link
Contributor

@nikolasdehor nikolasdehor commented Feb 26, 2026

Problema

Em build-state-manager.js:400, getLastCheckpoint() acessa this._state.checkpoints.length diretamente. Se this._state existe mas checkpoints é undefined (state carregado de JSON incompleto), ocorre TypeError: Cannot read property 'length' of undefined.

Mesmo bug em getCheckpoint() (linha 416): acessa .checkpoints.find() sem guard.

Correção

 getLastCheckpoint() {
-  if (!this._state || this._state.checkpoints.length === 0) {
+  if (!this._state || !this._state.checkpoints || this._state.checkpoints.length === 0) {
     return null;
   }

 getCheckpoint(checkpointId) {
-  if (!this._state) {
+  if (!this._state || !this._state.checkpoints) {
     return null;
   }

Validação

  • 49 testes do build-state-manager passando
  • Zero regressões

Closes #513

Summary by CodeRabbit

  • Bug Fixes
    • Improved checkpoint management stability with enhanced validation for missing or empty checkpoint data, ensuring more robust state handling.

Copilot AI review requested due to automatic review settings February 26, 2026 12:57
@vercel
Copy link

vercel bot commented Feb 26, 2026

@nikolasdehor is attempting to deploy a commit to the Pedro Valério Lopez's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai
Copy link

coderabbitai bot commented Feb 26, 2026

Walkthrough

Bug fix adding null/undefined guards to getLastCheckpoint() and getCheckpoint() methods in the build state manager. Both methods now safely check if the checkpoints array exists before accessing its properties, preventing TypeError when state is instantiated without a checkpoints property.

Changes

Cohort / File(s) Summary
Build State Manager Null Safety
.aiox-core/core/execution/build-state-manager.js
Added null/undefined guards for checkpoints array in getLastCheckpoint() and getCheckpoint() methods to prevent TypeError when checkpoints property is undefined or missing on state object.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~5 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the fix: adding null guards to getLastCheckpoint and getCheckpoint methods in the execution module.
Linked Issues check ✅ Passed The code changes directly address issue #513 by adding null guards to both getLastCheckpoint and getCheckpoint methods to prevent TypeError when checkpoints is undefined.
Out of Scope Changes check ✅ Passed All changes in build-state-manager.js are directly scoped to fixing the null guard issue described in #513; no unrelated modifications detected.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request addresses a defensive programming issue in the BuildStateManager where accessing this._state.checkpoints without first verifying it exists could cause a TypeError. The fix adds null guards to getLastCheckpoint() and getCheckpoint() methods to prevent crashes when the state's checkpoints property is undefined.

Changes:

  • Added null guard for this._state.checkpoints in getLastCheckpoint() method
  • Added null guard for this._state.checkpoints in getCheckpoint() method

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
.aios-core/core/execution/build-state-manager.js (1)

365-366: Consider adding a similar null guard here for consistency.

While saveCheckpoint already validates !this._state, the same corrupted-state scenario (state exists but checkpoints is undefined) could cause a TypeError at line 366. For defense-in-depth, consider initializing checkpoints if missing:

🛡️ Optional defensive initialization
     // Add to state
+    if (!this._state.checkpoints) {
+      this._state.checkpoints = [];
+    }
     this._state.checkpoints.push(checkpoint);

Alternatively, throw a more descriptive error if state integrity is compromised. This is optional and can be addressed separately if needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.aios-core/core/execution/build-state-manager.js around lines 365 - 366, The
push to this._state.checkpoints can throw if this._state exists but checkpoints
is undefined; in the saveCheckpoint method (or wherever
this._state.checkpoints.push(checkpoint) is called) add a defensive guard that
ensures this._state.checkpoints is an array before pushing (e.g. if
(!Array.isArray(this._state.checkpoints)) this._state.checkpoints = [];), or
alternatively throw a clear error indicating corrupted state; update the code
around the this._state.checkpoints.push(checkpoint) call to perform that
check/initialization to avoid a TypeError.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In @.aios-core/core/execution/build-state-manager.js:
- Around line 365-366: The push to this._state.checkpoints can throw if
this._state exists but checkpoints is undefined; in the saveCheckpoint method
(or wherever this._state.checkpoints.push(checkpoint) is called) add a defensive
guard that ensures this._state.checkpoints is an array before pushing (e.g. if
(!Array.isArray(this._state.checkpoints)) this._state.checkpoints = [];), or
alternatively throw a clear error indicating corrupted state; update the code
around the this._state.checkpoints.push(checkpoint) call to perform that
check/initialization to avoid a TypeError.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 63db79b and 2bc2be9.

📒 Files selected for processing (1)
  • .aios-core/core/execution/build-state-manager.js

coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 26, 2026
coderabbitai[bot]
coderabbitai bot previously approved these changes Feb 27, 2026
getLastCheckpoint() acessava this._state.checkpoints.length sem
verificar se checkpoints existe. State carregado de JSON incompleto
(sem a propriedade checkpoints) causa TypeError em runtime.

Adiciona guard !this._state.checkpoints em ambos os métodos.

Closes SynkraAI#513
@nikolasdehor
Copy link
Contributor Author

@Pedrovaleriolopez @oalanicolas, null guard em getLastCheckpoint/getCheckpoint no build-state-manager — previne crash quando não há checkpoints salvos. Fix da issue #513.

@codecov
Copy link

codecov bot commented Mar 11, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.aiox-core/core/execution/build-state-manager.js (2)

399-416: ⚠️ Potential issue | 🟠 Major

The getters are now defensive, but legacy/incomplete state files still fail before they can help.

This only masks the problem at the accessor layer. loadState() still validates checkpoints as required and throws on older/corrupted build-state.json, so the backwards-compatibility scenario described in the PR remains broken. The same invalid shape can also still trip saveCheckpoint() / getStatus() later if _state is injected directly.

A safer fix is to normalize state.checkpoints during load/migration instead of only guarding reads here.

Suggested direction
  loadState() {
    if (!fs.existsSync(this.stateFilePath)) {
      return null;
    }

    try {
      const content = fs.readFileSync(this.stateFilePath, 'utf-8');
      const state = JSON.parse(content);

+     // Backwards-compatible migration for older/incomplete state files
+     if (state.checkpoints == null) {
+       state.checkpoints = [];
+     }
+
      // Validate
      const validation = validateBuildState(state);
      if (!validation.valid) {
        throw new Error(`Invalid state file: ${validation.errors.join(', ')}`);
      }

As per coding guidelines, "Ensure backwards compatibility — core modules are consumed by all agents."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.aiox-core/core/execution/build-state-manager.js around lines 399 - 416,
loadState() currently enforces that state.checkpoints exists and throws on
legacy/corrupt build-state.json, so defensive getters (getLastCheckpoint,
getCheckpoint) only mask the symptom; normalize and sanitize checkpoints during
load/migration instead: in loadState() ensure this._state is created if missing,
coerce this._state.checkpoints to an array (e.g., [] when missing or not an
array), remove any non-object entries and ensure each checkpoint has an id (or
drop/repair entries), and update saveCheckpoint()/getStatus() to rely on the
normalized this._state.checkpoints so callers no longer receive an invalid
shape.

399-416: ⚠️ Potential issue | 🟡 Minor

Add test coverage for getCheckpoint() method.

The getLastCheckpoint() method is covered by the "should return null when no checkpoints" test in the Checkpoint Management suite. However, getCheckpoint(checkpointId) has no test coverage and should have explicit tests covering:

  • Return of null when state is missing
  • Return of null when checkpoints array is undefined/null
  • Successful lookup by checkpoint ID
  • Return of null when checkpoint ID is not found

Per coding guidelines, test coverage is required for new/modified functions in core modules.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.aiox-core/core/execution/build-state-manager.js around lines 399 - 416, Add
unit tests for the BuildStateManager.getCheckpoint(checkpointId) method: create
tests that (1) assert getCheckpoint returns null when this._state is
undefined/null, (2) assert it returns null when this._state.checkpoints is
undefined or null, (3) assert it returns the correct checkpoint object when a
checkpoint with the given id exists in this._state.checkpoints, and (4) assert
it returns null when no checkpoint with the given id is found. Use the existing
Checkpoint Management test suite pattern (the test that covers
getLastCheckpoint) to instantiate BuildStateManager, set up or omit the
_state/_state.checkpoints values, and call getCheckpoint(checkpointId) with
appropriate ids to verify the expected outcomes.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In @.aiox-core/core/execution/build-state-manager.js:
- Around line 399-416: loadState() currently enforces that state.checkpoints
exists and throws on legacy/corrupt build-state.json, so defensive getters
(getLastCheckpoint, getCheckpoint) only mask the symptom; normalize and sanitize
checkpoints during load/migration instead: in loadState() ensure this._state is
created if missing, coerce this._state.checkpoints to an array (e.g., [] when
missing or not an array), remove any non-object entries and ensure each
checkpoint has an id (or drop/repair entries), and update
saveCheckpoint()/getStatus() to rely on the normalized this._state.checkpoints
so callers no longer receive an invalid shape.
- Around line 399-416: Add unit tests for the
BuildStateManager.getCheckpoint(checkpointId) method: create tests that (1)
assert getCheckpoint returns null when this._state is undefined/null, (2) assert
it returns null when this._state.checkpoints is undefined or null, (3) assert it
returns the correct checkpoint object when a checkpoint with the given id exists
in this._state.checkpoints, and (4) assert it returns null when no checkpoint
with the given id is found. Use the existing Checkpoint Management test suite
pattern (the test that covers getLastCheckpoint) to instantiate
BuildStateManager, set up or omit the _state/_state.checkpoints values, and call
getCheckpoint(checkpointId) with appropriate ids to verify the expected
outcomes.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f8130659-5d4e-4b3a-a975-35e43209b628

📥 Commits

Reviewing files that changed from the base of the PR and between 52824bf and 7295587.

📒 Files selected for processing (1)
  • .aiox-core/core/execution/build-state-manager.js

@nikolasdehor
Copy link
Contributor Author

Fechando — o null guard em getLastCheckpoint/getCheckpoint foi mergeado via #581. Nosso PR era o original (aberto 26/fev, issue #513).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: build-state-manager getLastCheckpoint falha se checkpoints é undefined

2 participants