Skip to content

Not able to create a NIMService without the expose field, and error message is confusing #737

@xieshenzh

Description

@xieshenzh

1. Quick Debug Information

2. Issue or feature description

Briefly explain the issue in terms of expected behavior and current behavior.

Create a NIMService without setting expose field.

Error:
Error "Invalid value: "object": no such key: expose evaluating rule: .spec.expose.ingress is deprecated, and will be removed in a future release. If .spec.expose.ingress is set, please do not set .spec.expose.router.ingress." for field "spec".

3. Steps to reproduce the issue

Detailed steps to reproduce the issue.

Create a NIMService without setting expose field.

For example:

apiVersion: apps.nvidia.com/v1alpha1
kind: NIMService
metadata:
  name: meta-llama3-8b-instruct
spec:
  image:
    pullPolicy: IfNotPresent
    pullSecrets:
      - ngc-secret
    repository: nvcr.io/nim/meta/llama-3.1-8b-instruct
    tag: 1.15.4
  storage:
    nimCache:
      name: llama-3-1-8b-instruct
      profile: '10e5c5c7b0037e16bc74e9ec32942256bf73fda9902c2697b6cbd8fe94b8b47e'
  replicas: 1
  tolerations:
    - effect: NoSchedule
      key: g5-gpu
      operator: Exists
  authSecret: ngc-api-secret

4. Information to attach

Analysis from claude:

 The issue is likely related to how Kubernetes handles struct zero values and CEL's has() function. Let me explain what's probably happening.

  The Problem

  Even when you don't set spec.expose in your YAML, Kubernetes may initialize the Expose struct with zero values (empty structs) rather than leaving it as nil. This is because in the type definition at line 121 in nimservice_types.go:

  Expose Expose `json:"expose,omitempty"`

  The Expose field is not a pointer - it's a value type. This means:

  1. Even with omitempty, if any nested field gets a default value, the entire struct exists
  2. Looking at line 117 in common_types.go, Service.Port has a default:
  // +kubebuilder:default:=8000
  Port *int32 `json:"port,omitempty"`
  3. This default value causes spec.expose.service to exist, which causes spec.expose to exist

  How CEL's has() Evaluates

  In CEL:
  - has(self.expose.ingress) returns true even for an empty struct (zero value)
  - has(self.expose.router) returns true even for an empty struct
  - has(self.expose.router.ingress) might also return true if router.ingress exists as an empty struct

  The validation fails because the CEL expression checks if these fields exist (even as empty structs), not whether they have meaningful values.

Metadata

Metadata

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions