Skip to content

google-auth-library: missing await makes the GOOGLE_APPLICATION_CREDENTIALS error-context catch block unreachable #8799

Description

@heychs

Please make sure you have searched for information in the following guides.

Library Name

google-auth-library (core/packages/google-auth-library-nodejs)

A screenshot that you have tested with "Try this API".

N/A — this is not an autogenerated API client. The bug is in the handwritten
google-auth-library core (local credential-file loading and error handling);
no API call is involved.

Link to the code that reproduces this issue. A link to a public Github Repository or gist with a minimal reproduction.

https://github.com/heychs/repro-google-cloud-node-8799

A step-by-step description of how to reproduce the issue, based on the linked reproduction.

  1. git clone https://github.com/heychs/repro-google-cloud-node-8799 && cd repro-google-cloud-node-8799
  2. npm install
  3. npm run repro

The script points GOOGLE_APPLICATION_CREDENTIALS at a nonexistent file and
calls new GoogleAuth().getClient(). Observed output (google-auth-library 10.6.2):

error message: The file at /nonexistent/creds.json does not exist, or it is not a file. ENOENT: no such file or directory, lstat '/nonexistent'
has documented prefix? false

A clear and concise description of what the bug is, and what you expected to happen.

GoogleAuth._tryGetApplicationCredentialsFromEnvironmentVariable() wraps its
file-loading call in a try/catch whose purpose is to prefix load errors
with a diagnostic pointing at the GOOGLE_APPLICATION_CREDENTIALS environment
variable:

try {
  return this._getApplicationCredentialsFromFilePath(
    credentialsPath,
    options,
  );
} catch (e) {
  if (e instanceof Error) {
    e.message = `Unable to read the credential file specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable: ${e.message}`;
  }

  throw e;
}

However, _getApplicationCredentialsFromFilePath() is an async function and
the call is returned without await. An async function never throws
synchronously — all of its failures surface as a rejected promise — so the
catch block is unreachable (dead code). The rejection propagates to the
caller untouched, and the intended message prefix is never added.

The credential-loading failure itself still propagates correctly; the impact is
diagnostic quality. When GOOGLE_APPLICATION_CREDENTIALS points at a missing,
unreadable, or malformed file, users get a bare error (e.g. a raw ENOENT
lstat message, or a SyntaxError from JSON.parse) with nothing telling them
the file was selected via GOOGLE_APPLICATION_CREDENTIALS — which is exactly
the context the dead catch block was written to provide.

Expected: the error message starts with
Unable to read the credential file specified by the GOOGLE_APPLICATION_CREDENTIALS environment variable: ....

Actual: the unprefixed underlying error is thrown; the catch block never
executes.

The fix is a one-liner: return await this._getApplicationCredentialsFromFilePath(...)
so the rejection is caught inside the enclosing try. I have the fix plus a
unit test ready and will open a PR referencing this issue.

A clear and concise description WHY you expect this behavior, i.e., was it a recent change, there is documentation that points to this behavior, etc. **

The catch block itself documents the intended behavior — the prefixed message
exists in the source but is unreachable, so this is clearly not working as the
author intended. (The existing unit test for this path,
'tryGetApplicationCredentialsFromEnvironmentVariable should handle invalid environment variable'
in test/test.googleauth.ts, only asserts that something throws, so it does
not catch the missing prefix.) This is long-standing — the missing await is
present at least as far back as google-auth-library v6.

  • OS: any
  • Node.js: any supported
  • google-auth-library version: current main / 10.6.2

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions