Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/tolerate-non-numeric-step.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@e2b/python-sdk": patch
---

fix(python-sdk): don't crash the build error path on a non-numeric reason.step
10 changes: 7 additions & 3 deletions packages/python-sdk/e2b/template/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -406,27 +406,31 @@ def pad_octal(mode: int) -> str:
return f"{mode:04o}"


def get_build_step_index(step: str, stack_traces_length: int) -> int:
def get_build_step_index(step: str, stack_traces_length: int) -> Optional[int]:
"""
Get the array index for a build step based on its name.

Special steps:
- BASE_STEP_NAME: Returns 0 (first step)
- FINALIZE_STEP_NAME: Returns the last index
- Numeric strings: Converted to number
- Anything else: None (no matching local stack trace)

:param step: Build step name or number as string
:param stack_traces_length: Total number of stack traces (used for FINALIZE_STEP_NAME)

:return: Index for the build step
:return: Index for the build step, or None if the step has no usable index
"""
if step == BASE_STEP_NAME:
return 0

if step == FINALIZE_STEP_NAME:
return stack_traces_length - 1

return int(step)
try:
return int(step)
except ValueError:
return None


def read_gcp_service_account_json(
Expand Down
2 changes: 1 addition & 1 deletion packages/python-sdk/e2b/template_async/build_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ async def poll_status() -> TemplateBuildStatusResponse:
step_index = get_build_step_index(
build_status.reason.step, len(stack_traces)
)
if step_index < len(stack_traces):
if step_index is not None and 0 <= step_index < len(stack_traces):
traceback = stack_traces[step_index]

raise BuildException(
Expand Down
2 changes: 1 addition & 1 deletion packages/python-sdk/e2b/template_sync/build_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,7 @@ def poll_status() -> TemplateBuildStatusResponse:
step_index = get_build_step_index(
build_status.reason.step, len(stack_traces)
)
if step_index < len(stack_traces):
if step_index is not None and 0 <= step_index < len(stack_traces):
traceback = stack_traces[step_index]

raise BuildException(
Expand Down
21 changes: 21 additions & 0 deletions packages/python-sdk/tests/test_build_step_index.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from e2b.template.consts import BASE_STEP_NAME, FINALIZE_STEP_NAME
from e2b.template.utils import get_build_step_index


def test_base_maps_to_first():
assert get_build_step_index(BASE_STEP_NAME, 5) == 0


def test_finalize_maps_to_last():
assert get_build_step_index(FINALIZE_STEP_NAME, 5) == 4


def test_numeric_string_maps_to_index():
assert get_build_step_index("3", 5) == 3


def test_non_numeric_step_returns_none():
# e2b Cloud itself reports "optimize" / "resize-disk" for those phases.
# None means "no matching local stack trace", not an error.
assert get_build_step_index("optimize", 5) is None
assert get_build_step_index("RUN apt-get update", 5) is None