Skip to content

fix: surface bad request field violations#131

Open
nicholaspun-wandb wants to merge 1 commit into
mainfrom
npun/surface-bad-request-violations
Open

fix: surface bad request field violations#131
nicholaspun-wandb wants to merge 1 commit into
mainfrom
npun/surface-bad-request-violations

Conversation

@nicholaspun-wandb

Copy link
Copy Markdown
Collaborator

Description

Raise CWSandboxValidationError and surface details from backend BadRequest.field_violations to the user.

Testing

  • Updated tests
  • Ran the following script locally, suite:sandbox-e2e is an invalid tag, so the sandbox create will error:
import wandb
from wandb.sandbox import Sandbox

wandb.login()

with Sandbox.run(
    container_image="busybox:latest", 
    tags=["suite:sandbox-e2e"]
) as sb:
    print(sb.sandbox_id)

Before (tag name violation not mentioned):

uv run python min-tags.py
wandb: [wandb.login()] Loaded credentials for https://api.wandb.ai from /Users/nicholaspun/.netrc.
wandb: Currently logged in as: nicholas-pun (wandb) to https://api.wandb.ai. Use `wandb login --relogin` to force relogin
Traceback (most recent call last):
  File "/Users/nicholaspun/Documents/test-wb-sandbox/.venv/lib/python3.11/site-packages/cwsandbox/_sandbox.py", line 2162, in _start_async
    response = await self._stub.Start(
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nicholaspun/Documents/test-wb-sandbox/.venv/lib/python3.11/site-packages/grpc/aio/_call.py", line 329, in __await__
    raise _create_rpc_error(
grpc.aio._call.AioRpcError: <AioRpcError of RPC that terminated with:
	status = StatusCode.INVALID_ARGUMENT
	details = ""
	debug_error_string = "UNKNOWN:Error received from peer ipv4:166.19.70.19:443 {grpc_status:3, grpc_message:""}"
>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/nicholaspun/Documents/test-wb-sandbox/min-tags.py", line 6, in <module>
    with Sandbox.run(
         ^^^^^^^^^^^^
  File "/Users/nicholaspun/Documents/test-wb-sandbox/.venv/lib/python3.11/site-packages/cwsandbox/_sandbox.py", line 850, in run
    sandbox.start().result()
  File "/Users/nicholaspun/Documents/test-wb-sandbox/.venv/lib/python3.11/site-packages/cwsandbox/_types.py", line 78, in result
    return self._future.result(timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nicholaspun/.local/share/uv/python/cpython-3.11.11-macos-aarch64-none/lib/python3.11/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/nicholaspun/.local/share/uv/python/cpython-3.11.11-macos-aarch64-none/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/Users/nicholaspun/Documents/test-wb-sandbox/.venv/lib/python3.11/site-packages/cwsandbox/_sandbox.py", line 2523, in _start_and_discard
    await self._start_async()
  File "/Users/nicholaspun/Documents/test-wb-sandbox/.venv/lib/python3.11/site-packages/cwsandbox/_sandbox.py", line 2166, in _start_async
    raise _translate_rpc_error(e, operation="Start sandbox") from e
cwsandbox.exceptions.SandboxError: Start sandbox failed: <AioRpcError of RPC that terminated with:
	status = StatusCode.INVALID_ARGUMENT
	details = ""
	debug_error_string = "UNKNOWN:Error received from peer ipv4:166.19.70.19:443 {grpc_status:3, grpc_message:""}"
>

After (tag violation surfaced with violation reason):

PYTHONPATH=/Users/nicholaspun/Documents/cwsandbox-client/src uv run python min-tags.py
wandb: [wandb.login()] Loaded credentials for https://api.wandb.ai from /Users/nicholaspun/.netrc.
wandb: Currently logged in as: nicholas-pun (wandb) to https://api.wandb.ai. Use `wandb login --relogin` to force relogin
Traceback (most recent call last):
  File "/Users/nicholaspun/Documents/cwsandbox-client/src/cwsandbox/_sandbox.py", line 2174, in _start_async
    response = await self._stub.Start(
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nicholaspun/Documents/test-wb-sandbox/.venv/lib/python3.11/site-packages/grpc/aio/_call.py", line 329, in __await__
    raise _create_rpc_error(
grpc.aio._call.AioRpcError: <AioRpcError of RPC that terminated with:
	status = StatusCode.INVALID_ARGUMENT
	details = ""
	debug_error_string = "UNKNOWN:Error received from peer ipv4:166.19.70.19:443 {grpc_status:3, grpc_message:""}"
>

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/Users/nicholaspun/Documents/test-wb-sandbox/min-tags.py", line 6, in <module>
    with Sandbox.run(
         ^^^^^^^^^^^^
  File "/Users/nicholaspun/Documents/cwsandbox-client/src/cwsandbox/_sandbox.py", line 861, in run
    sandbox.start().result()
  File "/Users/nicholaspun/Documents/cwsandbox-client/src/cwsandbox/_types.py", line 78, in result
    return self._future.result(timeout)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/nicholaspun/.local/share/uv/python/cpython-3.11.11-macos-aarch64-none/lib/python3.11/concurrent/futures/_base.py", line 456, in result
    return self.__get_result()
           ^^^^^^^^^^^^^^^^^^^
  File "/Users/nicholaspun/.local/share/uv/python/cpython-3.11.11-macos-aarch64-none/lib/python3.11/concurrent/futures/_base.py", line 401, in __get_result
    raise self._exception
  File "/Users/nicholaspun/Documents/cwsandbox-client/src/cwsandbox/_sandbox.py", line 2535, in _start_and_discard
    await self._start_async()
  File "/Users/nicholaspun/Documents/cwsandbox-client/src/cwsandbox/_sandbox.py", line 2178, in _start_async
    raise _translate_rpc_error(e, operation="Start sandbox") from e
cwsandbox.exceptions.SandboxValidationError: Start sandbox failed: field violations: tags[0]: tags may contain letters, numbers, '.', '_' or '-', must be 59 characters or fewer, must end with a letter or number, and may start with '.', '_' or '-'

@nicholaspun-wandb nicholaspun-wandb self-assigned this May 26, 2026
@nicholaspun-wandb nicholaspun-wandb requested a review from a team as a code owner May 26, 2026 16:49
@nicholaspun-wandb nicholaspun-wandb force-pushed the npun/surface-bad-request-violations branch from b6dbc0b to 1c4721a Compare June 9, 2026 19:51
@nicholaspun-wandb nicholaspun-wandb force-pushed the npun/surface-bad-request-violations branch from 1c4721a to 0b6edfc Compare June 11, 2026 21:07
@nicholaspun-wandb

nicholaspun-wandb commented Jun 11, 2026

Copy link
Copy Markdown
Collaborator Author

Integration tests run:

uv run --no-sync pytest tests/integration/ -p wandb.sandbox -n auto

========================================================== short test summary info ==========================================================
FAILED tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_capacity_filter - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
FAILED tests/integration/cwsandbox/test_discovery.py::TestGetProfile::test_get_nonexistent_profile - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
FAILED tests/integration/cwsandbox/test_file_system_snapshot.py::test_snapshot_on_stop - cwsandbox.exceptions.SandboxError: Start sandbox failed: no suitable runner available
FAILED tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_filter_nonexistent_profile - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
FAILED tests/integration/cwsandbox/test_discovery.py::TestGetRunner::test_get_nonexistent_runner - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
FAILED tests/integration/cwsandbox/test_file_system_snapshot.py::test_list_get_delete_snapshot - cwsandbox.exceptions.SandboxError: Start sandbox failed: no suitable runner available
ERROR tests/integration/cwsandbox/test_discovery.py::TestListProfiles::test_filter_by_egress_mode - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListProfiles::test_filter_by_service_exposure_mode - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestGetProfile::test_get_existing_profile - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListProfiles::test_profile_fields_populated - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListProfiles::test_returns_profiles - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListProfiles::test_filter_by_runner_id - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestGetProfile::test_get_profile_without_runner_id - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_filter_by_profile_name - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListProfiles::test_filter_by_architecture - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestCrossReference::test_profile_runner_ids_exist - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_include_resources_false_default - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_filter_by_runner_group_id - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_filter_by_architecture - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestGetRunner::test_get_runner_always_has_full_details - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_runner_fields_populated - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestGetRunner::test_get_existing_runner - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_include_resources_true - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestListRunners::test_returns_runners - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_discovery.py::TestCrossReference::test_runner_profiles_match_list_profiles - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_sandbox.py::test_sandbox_pinned_to_runner - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_sandbox.py::test_sandbox_pinned_to_profile_and_runner - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
ERROR tests/integration/cwsandbox/test_sandbox.py::test_sandbox_pinned_to_profile - cwsandbox.exceptions.CWSandboxAuthenticationError: Permission denied: W&B auth is not allowed for this sandbox operation
======================================= 6 failed, 88 passed, 2 skipped, 22 errors in 62.83s (0:01:02) =======================================
CWSANDBOX_BASE_URL=http://localhost:8080 \
CWSANDBOX_API_KEY=key1 \
uv run pytest \
tests/integration/cwsandbox/test_discovery.py \
tests/integration/cwsandbox/test_sandbox.py::test_sandbox_pinned_to_profile_and_runner \
tests/integration/cwsandbox/test_sandbox.py::test_sandbox_pinned_to_profile \
tests/integration/cwsandbox/test_sandbox.py::test_sandbox_pinned_to_runner \
tests/integration/cwsandbox/test_file_system_snapshot.py \
-n 6
============================================================ test session starts ============================================================
platform darwin -- Python 3.11.10, pytest-9.0.2, pluggy-1.6.0
rootdir: /Users/nicholaspun/Documents/cwsandbox-client
configfile: pyproject.toml
plugins: anyio-4.12.1, xdist-3.8.0, asyncio-1.3.0, dotenv-0.5.2, cov-7.0.0
asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
6 workers [29 items]    
.............................                                                                                                         [100%]
====================================================== 29 passed in 221.13s (0:03:41) =======================================================

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.

1 participant