# OneOf Constraint Bug - Root Cause Analysis ## Problem Statement VPC instance creation fails with error: **"Expected only one oneOf fields to be set: got 0"** ## Error Details - Test: `TestE2ENodePoolInstanceTypeSelection` - Circuit breaker triggers after 4-6 failures - Error message: "creating instance: Expected only one oneOf fields to be set: got 0" ## Root Cause Identified The code at `pkg/providers/vpc/instance/provider.go:673` calls: ```go instance, err := vpcClient.CreateInstance(ctx, instancePrototype) ``` However, the **instancePrototype** type is: ```go *vpcv1.InstancePrototypeInstanceByImageInstanceByImageInstanceByNetworkAttachment ``` The VPC SDK's `CreateInstance` signature requires: ```go func (vpc *VpcV1) CreateInstance(createInstanceOptions *CreateInstanceOptions) (result *Instance, response *core.DetailedResponse, err error) ``` ## The Issue The `vpcClient.CreateInstance` wrapper method is likely accepting the raw prototype and wrapping it in `CreateInstanceOptions`, BUT the IBM VPC SDK has a discriminated union (oneOf) pattern for the `InstancePrototype` field within `CreateInstanceOptions`. When the prototype struct is wrapped or marshaled, the interface fields (`ImageIdentityIntf`, `ZoneIdentityIntf`, etc.) are being lost or set to nil because: 1. **The prototype struct hierarchy is wrong** - The code uses `InstancePrototypeInstanceByImageInstanceByImageInstanceByNetworkAttachment` which is too specific 2. **Interface field marshaling issue** - The `json:",inline"` or similar tags in the SDK cause interface fields to be omitted when marshaling 3. **Wrapper function might be converting wrong** - If there's a wrapper that converts the prototype to `CreateInstanceOptions`, it might not be preserving the interface types correctly ## Evidence from Logs Controller logs show (line 654-660): ```go if jsonBytes, jsonErr := json.MarshalIndent(instancePrototype, "", " "); jsonErr == nil { logger.Info("VPC CreateInstance JSON payload", "instance_name", nodeClaim.Name, "json_payload", string(jsonBytes)) } ``` The JSON payload from the logs shows that fields WITHOUT `omitempty` are missing: - `Image ImageIdentityIntf` - NO omitempty, but MISSING in JSON - `Zone ZoneIdentityIntf` - NO omitempty, but MISSING in JSON - `PrimaryNetworkAttachment *InstanceNetworkAttachmentPrototype` - NO omitempty, but MISSING in JSON This indicates the interface values are being set to **nil** during marshaling or prototype wrapping. ## Solution Approach Need to investigate the `vpcClient.CreateInstance` wrapper method implementation. The fix will likely involve: 1. **Check the wrapper implementation** - See how it converts the prototype to `CreateInstanceOptions` 2. **Use correct prototype type** - May need to use a different prototype type or create `CreateInstanceOptions` directly 3. **Ensure interface fields are preserved** - The wrapper must correctly handle interface type fields ## Next Steps 1. Find the `vpcClient` wrapper interface/implementation 2. Check how `CreateInstance` is wrapping the prototype 3. Verify if the correct oneOf discriminator is being set 4. Test with explicit `CreateInstanceOptions` construction instead of passing raw prototype ## Test Instance Details - Instance Profile: `bx2-2x8`, `bx2-4x16`, `mx2-2x16`, `cx2-4x8` - Zone: `eu-de-2` - Image: `r010-17a6c2b3-c93b-4018-87ca-f078ef21e02b` - VPC: `r010-2b1c3cdc-a678-4eda-86af-731130de1c0a` - Subnet: `02c7-dc97437a-1b67-41c9-9db9-a6b92a46963d` All values are set correctly in code (confirmed by debug logs), but become nil when sent to API.