oxidecomputer / oxidecomputer/omicron
Internet gateway accepts only one IP address, and the error blames the wrong object
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 572
- Forks
- 97
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 96
Description
While enabling networking tests for our PA suite, Claude found the following issue:
An internet gateway can hold at most one IP address. Attaching a second one fails — even
with a completely distinct name and IP — because of a UNIQUE index on
internet_gateway_ip_address (internet_gateway_id).
The failure surfaces as 400 ObjectAlreadyExists: already exists: internet-gateway-ip-address "<new-name>", naming an object that has never existed. The real
constraint is on the parent gateway, not the name, so the message points at the wrong thing.
Environment
- Rack: racklette
berlin - Software version:
22.0.0-0.ci+git35ee33351a2 - Reproduced: 2026-08-10, via
oxideCLI
Steps to reproduce
1. Attach the first address — succeeds
$ oxide internet-gateway address create --name addr-one --description first \
--address 192.0.2.10 --gateway igw1 --vpc default --project igw-bug-repro
{
"address": "192.0.2.10",
"description": "first",
"id": "19b7ee69-ebea-4550-90df-2a4b902d244a",
"internet_gateway_id": "6c4c339a-152a-44df-8e24-4003dee26ac8",
"name": "addr-one",
"time_created": "2026-08-10T18:26:52.705847Z",
"time_modified": "2026-08-10T18:26:52.705847Z"
}
2. Attach a second address, distinct name and distinct IP — fails
$ oxide internet-gateway address create --name addr-two --description second \
--address 192.0.2.11 --gateway igw1 --vpc default --project igw-bug-repro
error
Error Response: status: 400 Bad Request; value: Error {
error_code: Some("ObjectAlreadyExists"),
message: "already exists: internet-gateway-ip-address \"addr-two\"",
request_id: "19bd3017-73dd-45ce-9af3-07f2d009e06e"
}
addr-two did not exist before this call.
3. Confirm only one address is present
$ oxide internet-gateway address list --gateway igw1 --vpc default --project igw-bug-repro
[
{
"address": "192.0.2.10",
"name": "addr-one",
...
}
]
4. Delete the first address, then re-run the call that just failed — now succeeds
The name was never the problem, since we can now create it.
$ oxide internet-gateway address delete --address addr-one --gateway igw1 \
--vpc default --project igw-bug-repro
$ oxide internet-gateway address create --name addr-two --description second \
--address 192.0.2.11 --gateway igw1 --vpc default --project igw-bug-repro
{
"address": "192.0.2.11",
"name": "addr-two",
"id": "62c417c1-e8c1-49cf-afba-1f989bec9e94",
"internet_gateway_id": "6c4c339a-152a-44df-8e24-4003dee26ac8",
...
}
5. Contrast: two IP pool links on the same gateway both succeed
$ oxide internet-gateway ip-pool attach --name pool-link-one --ip-pool default \
--gateway igw1 --vpc default --project igw-bug-repro
"name": "pool-link-one",
$ oxide internet-gateway ip-pool attach --name pool-link-two --ip-pool default \
--gateway igw1 --vpc default --project igw-bug-repro
"name": "pool-link-two",
$ oxide internet-gateway ip-pool list --gateway igw1 --vpc default --project igw-bug-repro
"name": "pool-link-one",
"name": "pool-link-two",
Expected behavior
Either:
- a gateway accepts multiple IP addresses, mirroring how it accepts multiple IP pools; or
- if one address per gateway is deliberate, the API returns an error that says so
(e.g.400explaining the gateway already has an address), and the limit is documented.
Actual behavior
The second attach fails with ObjectAlreadyExists naming an object that does not exist,
giving no indication that the gateway's capacity is the issue.
The misleading message comes from nexus/db-queries/src/db/datastore/vpc.rs:1926
(internet_gateway_attach_ip_address), which maps every database error through:
AsyncInsertError::DatabaseError(e) => public_error_from_diesel(
e,
ErrorHandler::Conflict(
ResourceType::InternetGatewayIpAddress,
name.as_str(), // <-- the NEW row's name
),
),
The unique violation fires on internet_gateway_id, but the handler labels the conflict with
the name of the row being inserted — hence already exists: internet-gateway-ip-address "addr-two".
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in nexus/db-queries/src/db/datastore/vpc.rs:1926, in internet_gateway_attach_ip_address, and inspect how the unique violation on internet_gateway_id is mapped through AsyncInsertError and public_error_from_diesel. Check the surrounding networking behavior and tests, then make the reported result accurately reflect whether the gateway limit is intentional; done means the second-address case no longer blames the new address and the intended behavior is covered.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- backend-api-design, databases
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 62/100