{"record":{"id":"126e77eaefd75fb8","repo":"rancher/rancher","slug":"invalid-subscriptionid","errorCode":null,"errorMessage":"invalid subscriptionId","messagePattern":"invalid subscriptionId","errorType":"http","errorClass":null,"httpStatus":400,"severity":"error","filePath":"pkg/api/norman/customization/aks/handler.go","lineNumber":328,"sourceCode":"\t\t\treturn http.StatusOK, nil\n\t\t}\n\t}\n\n\treturn httperror.InvalidBodyContent.Status, fmt.Errorf(\"cloud credential not found\")\n}\n\nfunc (h *handler) getCredentialsFromBody(req *http.Request, cap *Capabilities) (int, error) {\n\traw, err := io.ReadAll(req.Body)\n\tif err != nil {\n\t\treturn http.StatusBadRequest, fmt.Errorf(\"cannot read request body: %v\", err)\n\t}\n\n\tif err = json.Unmarshal(raw, &cap); err != nil {\n\t\treturn http.StatusBadRequest, fmt.Errorf(\"cannot parse request body: %v\", err)\n\t}\n\n\tif cap.SubscriptionID == \"\" {\n\t\treturn http.StatusBadRequest, fmt.Errorf(\"invalid subscriptionId\")\n\t}\n\tif cap.TenantID == \"\" {\n\t\treturn http.StatusBadRequest, fmt.Errorf(\"invalid tenantId\")\n\t}\n\tif cap.ClientID == \"\" {\n\t\treturn http.StatusBadRequest, fmt.Errorf(\"invalid clientId\")\n\t}\n\tif cap.ClientSecret == \"\" {\n\t\treturn http.StatusBadRequest, fmt.Errorf(\"invalid clientSecret\")\n\t}\n\n\tclientEnvironment := \"\"\n\tif cap.Environment != \"\" {\n\t\tclientEnvironment = cap.Environment\n\t}\n\t_, azureEnvironment := GetEnvironment(clientEnvironment)\n\n\tif cap.BaseURL == \"\" {","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/rancher/rancher/blob/932558d4e68565aff2d2f36e89ec4a391b06e7c5/pkg/api/norman/customization/aks/handler.go#L310-L346","documentation":"getCredentialsFromBody (handler.go:317) parses an inline credential payload for AKS lister endpoints and requires a non-empty subscriptionId string; an empty value yields 400 'invalid subscriptionId'. Unlike checkCredentials (which says 'must provide subscriptionId'), this path is used when credentials are pasted directly in the request body.","triggerScenarios":"POSTing to an aks lister action with credentials inline where subscriptionId is missing, empty, or under a differently-cased key (SubscriptionId) that json.Unmarshal ignores.","commonSituations":"UI 'paste credentials' flow left subscription blank; partial payload copied from the cloud credential edit dialog; key casing drift after an SDK/UI update.","solutions":["Include subscriptionId as a non-empty string GUID in the request body","Use exact camelCase keys matching the API schema (subscriptionId, tenantId, clientId, clientSecret)","Copy the four values from 'az account show' to guarantee they are populated"],"exampleFix":"// before\nconst body = { tenantId, clientId, clientSecret, region };\n// after\nconst body = { subscriptionId, tenantId, clientId, clientSecret, region };","handlingStrategy":"validation","validationCode":"const isGuid = (s) => /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(s || '');\nif (!isGuid(body.subscriptionId)) throw new Error('subscriptionId (GUID) is required for inline AKS requests');","typeGuard":"function hasInlineAksCreds(b) {\n  return typeof b?.subscriptionId === 'string' && b.subscriptionId !== '';\n}","tryCatchPattern":"if (!hasInlineAksCreds(body)) { flagField('subscriptionId'); return; }\nconst resp = await post(listEndpoint, body);","preventionTips":["Source all four inline fields from one 'az account show' snapshot","Disable submit until every required field passes client validation","Keep field names camelCase to match the API schema exactly"],"tags":["aks","azure","validation","cloud-credentials","http-400"],"backgroundTag":null,"analyzedSha":"932558d4e68565aff2d2f36e89ec4a391b06e7c5","analyzedAt":"2026-08-16T04:37:02.125Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}