ToolJet/ToolJet · error · Error

Google OAuth "clientId" ${oauth_type === 'tooljet_app' ? 'en

Error message

Google OAuth "clientId" ${oauth_type === 'tooljet_app' ? 'environment variable' : 'config'} is missing

What it means

The Google Calendar plugin's authUrl() reads the OAuth clientId from either the GOOGLE_CLIENT_ID environment variable (when oauth_type === 'tooljet_app') or from source_options.client_id.value. If neither resolves to a truthy string, this plain Error is thrown before any redirect URL is built. It is a configuration-time failure surfaced at the first attempt to start OAuth.

Source

Thrown at marketplace/plugins/googlecalendar/lib/index.ts:25

} from '@tooljet-marketplace/common';
import { SourceOptions, ConvertedFormat, QueryResult } from './types';
import got, { Headers, OptionsOfTextResponseBody } from 'got';

export default class GoogleCalendar implements QueryService {
  authUrl(source_options: SourceOptions): string {
    const host = process.env.TOOLJET_HOST;
    const subpath = process.env.SUB_PATH;
    const fullUrl = `${host}${subpath ? subpath : '/'}`;
    const oauth_type = source_options.oauth_type.value;
    let clientId: string;
    if (oauth_type === 'tooljet_app') {
      clientId = process.env.GOOGLE_CLIENT_ID;
    } else {
      clientId = source_options?.client_id?.value;
    }
    const scope = 'https://www.googleapis.com/auth/calendar';
    if (!clientId) {
      throw new Error(
        `Google OAuth "clientId" ${oauth_type === 'tooljet_app' ? 'environment variable' : 'config'} is missing`
      );
    }

    const encodedScope = this.encodeOAuthScope(scope);
    const baseUrl =
      'https://accounts.google.com/o/oauth2/v2/auth' +
      `?response_type=code&client_id=${clientId}` +
      `&redirect_uri=${fullUrl}oauth2/authorize`;
    const authUrl = `${baseUrl}&scope=${encodedScope}&access_type=offline&prompt=consent`;
    return authUrl;
  }

  private encodeOAuthScope(scope: string): string {
    return encodeURIComponent(scope);
  }

  async run(

View on GitHub (pinned to 20602a8e10)

Solutions

  1. If using tooljet_app mode: set GOOGLE_CLIENT_ID (and GOOGLE_CLIENT_SECRET) in the server environment and restart the process.
  2. If using custom mode: open the datasource configuration and supply client_id.value (and client_secret.value) from the Google Cloud Console credential.
  3. Verify the value is a non-empty string — an empty-string env var still fails the !clientId check.
  4. Confirm source_options.oauth_type.value is one of 'tooljet_app' or a custom mode so the correct branch resolves clientId.

Example fix

// before (env empty)
// .env: GOOGLE_CLIENT_ID=

// after
// .env:
GOOGLE_CLIENT_ID=123456-abc.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=yourSecret

// OR, in datasource config (custom mode):
source_options = {
  oauth_type: { value: 'custom' },
  client_id: { value: '123456-abc.apps.googleusercontent.com' },
  client_secret: { value: 'yourSecret' }
};
Defensive patterns

Strategy: validation

Validate before calling

function resolveGoogleCalendarClientId(source_options, env = process.env) {
  const oauth_type = source_options?.oauth_type?.value;
  const clientId = oauth_type === 'tooljet_app'
    ? env.GOOGLE_CLIENT_ID
    : source_options?.client_id?.value;
  if (!clientId) {
    throw new Error(
      `Google OAuth clientId missing (mode=${oauth_type}). Set GOOGLE_CLIENT_ID env or client_id config.`
    );
  }
  return clientId;
}
resolveGoogleCalendarClientId(source_options);

Type guard

function hasGoogleCalendarClientId(source_options, env = process.env): boolean {
  const oauth_type = source_options?.oauth_type?.value;
  return oauth_type === 'tooljet_app'
    ? !!env.GOOGLE_CLIENT_ID
    : !!source_options?.client_id?.value;
}

Try / catch

try {
  const url = plugin.authUrl(source_options);
} catch (e) {
  if (/clientId.*missing/.test(e.message)) {
    // prompt operator to set GOOGLE_CLIENT_ID or fill client_id config
  }
  throw e;
}

Prevention

When it happens

Trigger: User selects 'tooljet_app' OAuth mode but the operator has not set GOOGLE_CLIENT_ID in the server env; OR user selects the custom ('config') mode but leaves the client_id field blank in the datasource config. Also triggered if oauth_type.value itself is undefined (the .value access would throw first, but a falsy clientId after that hits this branch).

Common situations: Fresh deploy of ToolJet without the GOOGLE_CLIENT_ID/GOOGLE_CLIENT_SECRET env vars set; misconfigured secret manager that injects an empty string; switching from tooljet_app to custom OAuth and forgetting to fill the new client_id field; copying source_options between environments and dropping the nested {value:"..."} structure.

Related errors


AI-assisted analysis of ToolJet/ToolJet@20602a8e10 (2026-08-13). Data as JSON: /api/errors/1593fe8678a537bf. Report an issue: GitHub.