twentyhq/twenty · error · Error

Missing env var: ${name}

Error message

Missing env var: ${name}

What it means

configure-partner-rls's requireEnv throws when a needed environment variable is empty/unset. The script loads .env.local (or ENV_FILE) via dotenv before this runs, so the var must be present in that file or the real environment. The known required vars are TWENTY_PARTNERS_API_URL and TWENTY_PARTNERS_API_KEY (plus any others requireEnv is later extended to read).

Source

Thrown at packages/twenty-apps/internal/twenty-partners/src/scripts/configure-partner-rls.ts:31

//    upsertFieldPermissions rejects out-of-band changes to app-owned roles
//    (ROLE_BELONGS_TO_ANOTHER_APPLICATION), so those must come from the manifest; if any
//    expected lock is missing, the script exits non-zero and tells you to re-sync.
//
// 3. Verifies Application field permissions the same way (pitch editable; rest locked).
//
// Usage:
//   yarn rls:configure          # against .env.local
//   yarn rls:configure:prod     # against .env.prod

import { config } from 'dotenv';
config({ path: process.env.ENV_FILE ?? '.env.local' });

import { PARTNER_ROLE_UNIVERSAL_IDENTIFIER } from 'src/constants/universal-identifiers';
import { PARTNER_ROLE_LABEL } from 'src/roles/partner.role';

const requireEnv = (name: string): string => {
  const value = process.env[name];
  if (!value) throw new Error(`Missing env var: ${name}`);
  return value;
};

const SIMPLE_TARGET_OBJECTS = [
  'partner',
  'person',
  'company',
  'partnerLink',
  'partnerService',
  'partnerContent',
  'application',
] as const;
type SimpleTargetObject = (typeof SIMPLE_TARGET_OBJECTS)[number];

// opportunity uses an OR group (handled separately), but still needs an existence check.
const ALL_TARGET_OBJECTS = [...SIMPLE_TARGET_OBJECTS, 'opportunity'] as const;

// Stable id for the OR predicate group — re-runs upsert in place instead of creating

View on GitHub (pinned to 1f5dd2bbd2)

Solutions

  1. Ensure .env.local (or .env.prod for :prod) defines TWENTY_PARTNERS_API_URL and TWENTY_PARTNERS_API_KEY.
  2. If using a non-default env file, run with ENV_FILE=./path/to/.env yarn rls:configure and confirm the path exists.
  3. Copy and fill the provided .env.example template for the target environment.
  4. Verify dotenv actually loaded the file (no typo in the path passed to config()).

Example fix

# before — .env.local missing or incomplete

# after — populate the required vars
TWENTY_PARTNERS_API_URL=https://your-workspace.twenty.app
TWENTY_PARTNERS_API_KEY=your-metadata-api-key
Defensive patterns

Strategy: validation

Validate before calling

import { config } from 'dotenv';
config({ path: process.env.ENV_FILE ?? '.env.local' });

const REQUIRED = ['TWENTY_PARTNERS_API_URL', 'TWENTY_PARTNERS_API_KEY'] as const;
const missing = REQUIRED.filter((k) => !process.env[k]);
if (missing.length > 0) {
  throw new Error(`Missing env vars in ${process.env.ENV_FILE ?? '.env.local'}: ${missing.join(', ')}`);
}

Prevention

When it happens

Trigger: requireEnv('TWENTY_PARTNERS_API_URL') or requireEnv('TWENTY_PARTNERS_API_KEY') reads an undefined/empty-string value. Happens when .env.local (or the ENV_FILE target) is missing, incomplete, or ENV_FILE points at a non-existent path so dotenv silently loads nothing.

Common situations: Fresh clone without copying .env.example to .env.local; running yarn rls:configure before populating secrets; pointing ENV_FILE at the wrong file; running rls:configure:prod against a .env.prod that lacks the key.

Related errors


AI-assisted analysis of twentyhq/twenty@1f5dd2bbd2 (2026-08-12). Data as JSON: /api/errors/a0e4e00f727927b8. Report an issue: GitHub.