Repository navigation
Conversation
Detect Docker APIError containing 'port is already allocated' during container creation and raise PortAlreadyInUse instead of the generic DockerContainerCreationFailedException. This provides users with accurate error information when a host port is already in use, particularly on container engines like Finch that bind ports during create() rather than start(). Add unit test to verify PortAlreadyInUse is raised when the Docker API returns a port allocation error during container creation. Fixes aws#9295
| if "port is already allocated" in str(ex): | ||
| raise PortAlreadyInUse(str(ex)) from ex |
There was a problem hiding this comment.
According to the issue #9347 (in expected result section), changing the error class to PortAlreadyInUse will mess up downstream error catching. The suggestion was simply to change the message.
🧪 Hands-on test plan (not run: external contributor)Commit Summary: Run the PR's new unit test and the existing container and local-service unit suites. Then feed realistic Docker APIErrors into the real Container.create() to compare the exception type and message on base vs PR, and check that unrelated create errors are unchanged. Finally, send an invoke through the real LocalLambdaHttpService Flask app whose runner hits Container.create(), to see whether the HTTP response for a port conflict changes from 501 ContainerCreationFailed to a generic 500 ServiceException. Why: The PR changes which exception Container.create() raises for a Docker APIError containing 'port is already allocated'. Callers (sam local invoke CLI, LocalLambdaHttpService, LocalApigwService, LambdaRuntime.create) handle ContainerCreationFailedException and PortAlreadyInUse differently, so the user-visible message and HTTP status can change. Real Docker binds ports at start(), not create(), and Finch is not available, so the run drives the real Container and LocalLambdaHttpService code with a mocked Docker client that raises realistic APIErrors (with an HTTP 500 response). The diff is 2 lines of library code plus a unit test, with no install-time code or new dependencies, so a local run is safe. Needs Docker: no Setup: Scenarios (5)S1: Run the PR's new unit test and the full existing test_container.py suite. Expected: On the PR checkout both commands exit 0; the new test passes and no existing test in test_container.py fails. (On base the -k selection finds no test, so only the second command is meaningful there.) S2: Main path: a realistic Docker APIError (HTTP 500 response, explanation holding the Finch-style 'port is already allocated' text) raised by containers.create() goes through the real Container.create(). Record the exception type, str() and __cause__, and whether the message is clean or includes the r… (compared with the base branch) Expected: PR: exit 0, prints TYPE=PortAlreadyInUse, CAUSE=APIError, IS_CREATED=False, and MSG contains 'port is already allocated'. Also record whether MSG includes the raw '500 Server Error for http+docker://localhost/v1.47/containers/create: Internal Server Error (' prefix; the PR uses str(ex), while start… S3: Edge cases: an unrelated create error (bad bind mount) must keep raising ContainerCreationFailedException with the 'check template' hint. The Docker Desktop wording 'Ports are not available' at create time shows whether that wording is handled too or still gets the misleading 'check template' messa… (compared with the base branch) Expected: 'other': on both base and PR, TYPE=ContainerCreationFailedException and MSG='Container creation failed: invalid mount config ... /nope, check template for potential issue'. 'notavail': on both base and PR, expect TYPE=ContainerCreationFailedException with the 'check template' hint, since the PR onl… S4: sam local start-lambda HTTP path: LocalLambdaHttpService catches ContainerCreationFailedException and returns 501 ContainerCreationFailed but does not catch PortAlreadyInUse. Send an invoke whose runner calls the real Container.create() with the port-allocated error and compare the HTTP status and … (compared with the base branch) Expected: Base, 'allocated': STATUS=501, ERRTYPE=ContainerCreationFailed, BODY holds 'Container creation failed: ... port is already allocated, check template ...'. PR, 'allocated': record the actual status. If it is STATUS=500 with ERRTYPE=Service / a generic ServiceException body and no port message, repor… S5: Check that the local-invoke, start-api and start-lambda unit suites that consume these exceptions still pass with the change. (compared with the base branch) Expected: Exit code 0 on the PR checkout with no failures; the pass count matches the base run. 🤖 Automated hands-on test — not a review approval · model claude-opus-5.5 · commit History (1)
|
Summary
This PR fixes issue #9295 by detecting the "port is already allocated" error during container creation and raising the appropriate
PortAlreadyInUseexception instead of the genericDockerContainerCreationFailedException.Problem
When container engines like Finch bind host ports during
containers.create()(rather than duringstart()like Docker), a port conflict results in a misleading error message:The error incorrectly directs users to check their template, when the actual issue is that the host port is already in use.
Solution
Modified
Container.create()insamcli/local/docker/container.pyto:APIErrormessage contains "port is already allocated"PortAlreadyInUse(the same exception already used in thestart()method for Docker)DockerContainerCreationFailedExceptionThis provides users with accurate error information regardless of which container engine they use or when the engine performs port binding.
Testing
test_create_raises_port_already_in_use_when_port_allocatedthat mocks a DockerAPIErrorwith "port is already allocated" messageDockerContainerCreationFailedException)PortAlreadyInUse)test_container.pycontinue to passFixes #9295
Target branch:
develop