{"record":{"id":"6ded996cce49e90f","repo":"opentofu/opentofu","slug":"unable-to-determine-credentials-file-path-w","errorCode":null,"errorMessage":"unable to determine credentials file path: %w","messagePattern":"unable to determine credentials file path: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/command/cliconfig/credentials.go","lineNumber":331,"sourceCode":"\t\t// Delegate entirely to the helper, then.\n\t\tif new == nil {\n\t\t\treturn s.helper.ForgetForHost(ctx, host)\n\t\t}\n\t\treturn s.helper.StoreForHost(ctx, host, new)\n\tdefault:\n\t\t// Should never happen because the above cases are exhaustive\n\t\treturn fmt.Errorf(\"invalid credentials location %#v\", loc)\n\t}\n}\n\nfunc (s *CredentialsSource) updateLocalHostCredentials(host svchost.Hostname, new svcauth.NewHostCredentials) error {\n\t// This function updates the local credentials file in particular,\n\t// regardless of whether a credentials helper is active. It should be\n\t// called only indirectly via updateHostCredentials.\n\n\tfilename, err := s.CredentialsFilePath()\n\tif err != nil {\n\t\treturn fmt.Errorf(\"unable to determine credentials file path: %w\", err)\n\t}\n\n\toldSrc, err := os.ReadFile(filename)\n\tif err != nil && !os.IsNotExist(err) {\n\t\treturn fmt.Errorf(\"cannot read %s: %w\", filename, err)\n\t}\n\n\tvar raw map[string]interface{}\n\n\tif len(oldSrc) > 0 {\n\t\t// When decoding we use a custom decoder so we can decode any numbers as\n\t\t// json.Number and thus avoid losing any accuracy in our round-trip.\n\t\tdec := json.NewDecoder(bytes.NewReader(oldSrc))\n\t\tdec.UseNumber()\n\t\terr = dec.Decode(&raw)\n\t\tif err != nil {\n\t\t\treturn fmt.Errorf(\"cannot read %s: %w\", filename, err)\n\t\t}","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/opentofu/opentofu/blob/3561785c48c1ce615e7c50261bd351f26053efa2/internal/command/cliconfig/credentials.go#L313-L349","documentation":"updateLocalHostCredentials (the writer behind storing/forgetting credentials, e.g. during tofu login) first asks s.CredentialsFilePath() for the target file. CredentialsFilePath just returns the path captured when the CredentialsSource was constructed; it only errors when the source was built without a resolvable path. In normal use Config.CredentialsSource already guarantees a path, so this is a defensive guard.","triggerScenarios":"Constructing a CredentialsSource directly (e.g. a zero-valued or test-built struct) instead of via Config.CredentialsSource or EmptyCredentialsSourceForTests, then calling an operation that persists credentials.","commonSituations":"Code (typically tests or forks) that hand-assembles CredentialsSource{} without setting credentialsFilePath and then triggers a store/forget of host credentials.","solutions":["Build the source through Config.CredentialsSource(helperPlugins) so the path comes from credentialsConfigFile()","For tests use EmptyCredentialsSourceForTests(path) with an explicit temp path","Check CredentialsFilePath() returns no error before attempting login/logout flows"],"exampleFix":"// before\nsrc := &CredentialsSource{}\nerr := src.StoreForHost(...)  // unable to determine credentials file path\n\n// after\nsrc, err := cfg.CredentialsSource(helperPlugins)\n// or, in tests:\nsrc := EmptyCredentialsSourceForTests(filepath.Join(t.TempDir(), \"credentials.tfrc.json\"))","handlingStrategy":"try-catch","validationCode":"if _, err := src.CredentialsFilePath(); err != nil {\n\t// source built without a path; rebuild it via cfg.CredentialsSource\n}","typeGuard":null,"tryCatchPattern":"func (s *store) save(host svchost.Hostname, creds svcauth.NewHostCredentials) (err error) {\n\tdefer func() {\n\t\tif err != nil && strings.Contains(err.Error(), \"unable to determine credentials file path\") {\n\t\t\terr = fmt.Errorf(\"credentials source misconfigured (no file path): %w\", err)\n\t\t}\n\t}()\n\treturn s.src.updateHostCredentials(context.Background(), host, creds)\n}","preventionTips":["Always construct CredentialsSource via Config.CredentialsSource or EmptyCredentialsSourceForTests","Never hand-initialize CredentialsSource literals outside package tests"],"tags":["credentials","api-misuse","internal"],"backgroundTag":null,"analyzedSha":"3561785c48c1ce615e7c50261bd351f26053efa2","analyzedAt":"2026-08-15T23:27:16.226Z","schemaVersion":2},"datasetVersion":"2026-08-16T03:17:38.424Z"}