{"record":{"id":"d06ad675e780a406","repo":"derailed/k9s","slug":"no-port-number-assigned","errorCode":null,"errorMessage":"no port number assigned","messagePattern":"no port number assigned","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/port/pf.go","lineNumber":119,"sourceCode":"\t\treturn s + p.containerPortNum\n\t}\n\treturn s + p.LocalPort\n}\n\n// String dumps the annotation.\nfunc (p *PFAnn) String() string {\n\treturn p.Container + \"::\" + p.LocalPort + \":\" + p.containerPortNum\n}\n\nfunc (p *PFAnn) PortNum() (string, error) {\n\tif p.ContainerPort.Type == intstr.Int {\n\t\treturn p.ContainerPort.String(), nil\n\t}\n\tif p.containerPortNum != \"\" {\n\t\treturn p.containerPortNum, nil\n\t}\n\n\treturn \"\", errors.New(\"no port number assigned\")\n}\n\nfunc (p *PFAnn) ToTunnel(address string) (PortTunnel, error) {\n\tvar pt PortTunnel\n\tport, err := p.PortNum()\n\tif err != nil {\n\t\treturn pt, err\n\t}\n\n\tpt.Address, pt.Container = address, p.Container\n\tpt.ContainerPort, pt.LocalPort = port, p.LocalPort\n\n\treturn pt, nil\n}\n","sourceCodeStart":101,"sourceCodeEnd":134,"githubUrl":"https://github.com/derailed/k9s/blob/2d3ccc6ba2ce98c3781bfc441bb3e884f072774f/internal/port/pf.go#L101-L134","documentation":"PFAnn.PortNum resolves the container side of a port-forward tunnel. If ContainerPort is an int it stringifies it; otherwise (intstr.String, i.e. a named port) it needs containerPortNum — the numeric value captured earlier from an explicit annotation token (pf.go:63/77) or from the matched port descriptor (pf.go:90). A named port with no resolved number leaves containerPortNum empty and PortNum fails, which aborts PFAnn.ToTunnel.","triggerScenarios":"A k9s.io/portforward annotation or descriptor referring to a named (string) container port whose numeric value was never resolved because the container spec lookup failed or the annotation used a name that does not exist; then building the tunnel with ToTunnel.","commonSituations":"Hand-written port-forward annotations using port names instead of numbers; referring to a name defined in a different container than the one in the annotation; races where the pod spec is not yet cached.","solutions":["Use the numeric container port in the annotation: container::localPort:9090 instead of a port name.","If using a named port, verify the name exists in that container's ports[] list so the resolver can map it to its number.","Check the annotation syntax matches 'container::local:container' — mis-parsed tokens leave containerPortNum empty."],"exampleFix":"# before\nk9s.io/portforward: \"app::8080:http\"   # 'http' unresolvable -> no port number assigned\n# after\nk9s.io/portforward: \"app::8080:8080\"","handlingStrategy":"validation","validationCode":"// resolve the number before building the tunnel\nif _, err := strconv.Atoi(ann.ContainerPort.String()); err != nil {\n    // named port: ensure it was matched to a numeric containerPortNum\n    if n, err := ann.PortNum(); err != nil {\n        _ = n // refuse: annotation must use a numeric container port\n        return fmt.Errorf(\"port %q has no number; use container::local:num\", ann.ContainerPort)\n    }\n}","typeGuard":"func hasPortNum(p *port.PFAnn) bool {\n    _, err := p.PortNum()\n    return err == nil\n}","tryCatchPattern":"t, err := ann.ToTunnel(address)\nif err != nil && strings.Contains(err.Error(), \"no port number assigned\") {\n    // rewrite annotation with a numeric container port and retry\n}","preventionTips":["Prefer numeric container ports in k9s.io/portforward annotations.","When using named ports, confirm the name exists in that container's ports[].","Follow the 'container::localPort:containerPort' annotation syntax exactly."],"tags":["go","kubernetes","port-forward","named-port","annotation"],"backgroundTag":null,"analyzedSha":"2d3ccc6ba2ce98c3781bfc441bb3e884f072774f","analyzedAt":"2026-08-15T16:09:14.432Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}