{"record":{"id":"e7db68db8eb4291e","repo":"mislav/hub","slug":"s-n-s","errorCode":null,"errorMessage":"%s\\n%s","messagePattern":"%s\\\\n%s","errorType":"exception","errorClass":null,"httpStatus":403,"severity":"error","filePath":"github/client.go","lineNumber":1259,"sourceCode":"\t\t\terrorSentences = append(errorSentences, fmt.Sprintf(\"Not allowed to change field \\\"%s\\\"\", err.Field))\n\t\t}\n\t}\n\n\tvar errorMessage string\n\tif len(errorSentences) > 0 {\n\t\terrorMessage = strings.Join(errorSentences, \"\\n\")\n\t} else {\n\t\terrorMessage = e.Message\n\t\tif action == \"getting current user\" && e.Message == \"Resource not accessible by integration\" {\n\t\t\terrorMessage = errorMessage + \"\\nYou must specify GITHUB_USER via environment variable.\"\n\t\t}\n\t}\n\tif errorMessage != \"\" {\n\t\terrStr = fmt.Sprintf(\"%s\\n%s\", errStr, errorMessage)\n\t}\n\n\tif ssoErr := ValidateGitHubSSO(e.Response); ssoErr != nil {\n\t\treturn fmt.Errorf(\"%s\\n%s\", errStr, ssoErr)\n\t}\n\n\tif scopeErr := ValidateSufficientOAuthScopes(e.Response); scopeErr != nil {\n\t\treturn fmt.Errorf(\"%s\\n%s\", errStr, scopeErr)\n\t}\n\n\treturn errors.New(errStr)\n}\n\n// ValidateGitHubSSO checks for the challenge via `X-Github-Sso` header\nfunc ValidateGitHubSSO(res *http.Response) error {\n\tif res.StatusCode != 403 {\n\t\treturn nil\n\t}\n\n\tsso := res.Header.Get(\"X-Github-Sso\")\n\tif !strings.HasPrefix(sso, \"required; url=\") {\n\t\treturn nil","sourceCodeStart":1241,"sourceCodeEnd":1277,"githubUrl":"https://github.com/mislav/hub/blob/5c547ed804368763064e51f3990851e267e88edd/github/client.go#L1241-L1277","documentation":"This is the tail of the HTTP error formatter (FormatError). After assembling the base error string (and any errorMessage from the response), it appends, on separate lines (%s\\n%s), either a GitHub SSO authorization challenge or an insufficient-OAuth-scopes warning when those validators detect them. The two-line message means the request failed AND the response carried an SSO or scope signal.","triggerScenarios":"Any REST call whose response triggers ValidateGitHubSSO (X-Github-Sso header present) or ValidateSufficientOAuthScopes (404/403 with scope mismatch), with errStr already containing the base HTTP error from the response errors.","commonSituations":"Accessing an org resource with a token not SSO-authorized for that org (common after enabling SAML SSO); using a classic PAT whose scopes (repo, read:org) don't cover the requested resource; enterprise deployments requiring fine-grained permissions.","solutions":["Follow the SSO authorization URL printed in the message (or in the X-Github-Sso header) to authorize your token for the organization.","Regenerate the token with the required scopes (repo, read:org, workflow as needed) if a scope warning is appended.","For fine-grained tokens, grant the token access to the specific organization/repository.","Update the stored token (e.g. `gh auth login` or re-run the library's auth flow) after changing scopes."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"req, _ := http.NewRequest(\"GET\", \"https://api.github.com/user\", nil)\nreq.Header.Set(\"Authorization\", \"Bearer \"+token)\nres, _ := http.DefaultClient.Do(req)\nif sso := res.Header.Get(\"X-Github-Sso\"); strings.HasPrefix(sso, \"required; url=\") {\n    return fmt.Errorf(\"authorize token at %s\", sso[strings.IndexByte(sso,'=')+1:])\n}","typeGuard":null,"tryCatchPattern":"if err != nil {\n    if strings.Contains(err.Error(), \"authorize your token\") || strings.Contains(err.Error(), \"OAuth\") {\n        return fmt.Errorf(\"token needs SSO authorization or more scopes: %w\", err)\n    }\n}","preventionTips":["Authorize the PAT for every SSO org you access (token → Configure SSO).","Create tokens with the full set of needed scopes: repo, read:org, workflow.","Re-authorize tokens after orgs enable or change SAML SSO.","Prefer GitHub Apps/fine-grained tokens for automation to avoid SSO per-token authorization."],"tags":["github-api","oauth-scopes","sso"],"backgroundTag":"github-token-scope-insufficient","analyzedSha":"5c547ed804368763064e51f3990851e267e88edd","analyzedAt":"2026-09-01T03:34:15.525Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}