Skip to content

The API said no

Two different mechanisms refuse things, and they look different. Read the first line of the error and you know which one you are dealing with.

  • Forbidden means RBAC: you are not allowed to touch that kind of object at all.
  • denied the request means a platform rule: your YAML is fine, but what it asks for is not permitted.

The second one matters because there is nothing to fix in the manifest. You need a different approach, and the message says which rule fired.

Forbidden on a kubectl command

Three causes, in the order they actually happen.

Your default namespace is not set. The command ran against default, which you have no access to. Check what the current context carries:

bash
kubectl config view --minify | grep namespace

If it says nothing, set it once, see Access and kubectl.

The resource is not one you may touch. Your namespace grants a specific list, and everything else is denied. Ask directly rather than guessing:

bash
kubectl auth can-i create scaledobjects
kubectl auth can-i list nodes

The full list is under Permissions and policies. Some grants are read-only, notably your quota and limit ranges, so get can succeed while edit is refused on the same object.

Cluster-scoped reads are always refused, including harmless-looking ones:

text
Error from server (Forbidden): nodes is forbidden: User "..." cannot list
resource "nodes" in API group "" at the cluster scope

That is intended, not a broken setup. It also means you cannot run kubectl get storageclass; the two class names are on Storage.

KUBECONFIG points somewhere else. Confirm where you are:

bash
kubectl config current-context

denied the request on apply

A platform rule fired. The shape is always the same:

text
Error from server: error when creating "app.yaml": admission webhook denied the
request: <the rule that fired, and why>

The full list of rules is under Permissions and policies. The ones that come up most often:

The message mentionsWhat it meansWhat to do
Volume type not allowedAn inline volume in the pod specAsk for storage with a PersistentVolumeClaim
Only ClusterIP Services are permittedNodePort, LoadBalancer or ExternalNameStay on ClusterIP and publish with an HTTPRoute
may not create CertificateA Certificate you wrote yourselfLet the annotation on your HTTPRoute issue it
Hostname is not allowed in namespaceA hostname your namespace may not serveSee below
must declare at least one hostnameAn HTTPRoute with no hostnamesAdd one
Free-tier namespaces may only use the nfs-rwx StorageClassBlock storage on the free tierUse nfs-rwx, see Free tier
may not tolerateA toleration that matches everythingRemove it and let the scheduler place the pod
may not set spec.nodeNameA hand-picked nodeRemove it
body.maxSizeA request body limit above the cap, or zeroSet an explicit size at or below 512 MiB

Hostname is not allowed in namespace

text
Hostname is not allowed in namespace 'tenant-7'. Tenant namespaces may only use
*.tenant-7.itsh.dev (paid) or *.tenant-7.itsh-apps.dev (free) subdomains or
hostnames listed in the itsh.dev/allowed-hostnames namespace annotation.

Your namespace owns one subdomain and can serve any name under it immediately. Anything else has to be added in the portal first, where you prove the domain is yours with a DNS record.

Free namespaces cannot use a custom domain at all. The full rules are on Gateway API.

Exec/attach is only allowed into gVisor-sandboxed pods

You tried to get a shell in a managed PostgreSQL pod. Those run outside the sandbox, and exec is only permitted into sandboxed pods, so this combination is refused.

It applies to PostgreSQL only. MariaDB and Dragonfly pods take a shell like any other. To run SQL, forward the port and use a local client, which is not affected. See Databases.

What's next