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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions