microsoft/aspire · error · Error

Cannot use null or undefined in reference expression

Error message

Cannot use null or undefined in reference expression

What it means

The generated TypeScript runtime's internal extractHandleForExpr builds reference expressions from handles (server objects) and string literals only. Passing null or undefined is ambiguous — the runtime cannot represent either in a reference expression — so it throws this Error up front instead of producing a malformed expression that would fail on the server side.

Solutions

  1. Check the value for null/undefined before passing it into the reference-expression helper, and substitute a string literal or a valid handle.
  2. Trace where the undefined came from — a failed lookup or optional property — and fix the source (provide a default, fix the key, or await an async lookup).
  3. If the value is legitimately optional, branch your code: build the expression only when the value exists, otherwise use a fallback string or skip the reference.
  4. Add TypeScript strict null checks (strictNullChecks) so the compiler flags possibly-undefined values before they reach the helper.

Example fix

// before
const endpoint = process.env.MAYBE_ENDPOINT;
const expr = value(endpoint);   // throws when undefined

// after
const endpoint = process.env.MAYBE_ENDPOINT ?? 'http://localhost:8080';
const expr = value(endpoint);
Defensive patterns

Strategy: validation

Validate before calling

function assertExprInput(v) {
  if (v === null || v === undefined) throw new TypeError('Reference expression value must be a handle or string, got ' + v);
  return v;
}
// call assertExprInput(x) before value(x)

Type guard

function isExprValue(v) { return typeof v === 'string' || (v !== null && v !== undefined && typeof v === 'object'); }

Try / catch

try {
  const expr = value(input);
} catch (err) {
  if (err instanceof Error && err.message.includes('null or undefined')) {
    // fall back to a default literal or skip building the expression
  }
}

Prevention

When it happens

Trigger: Calling a reference-expression building API (e.g. the `value`/expression helpers that call extractHandleForExpr) with null or undefined as the value — commonly from an unset variable, an optional field, or a failed lookup like env.get(...)/map lookup returning undefined.

Common situations: Optional endpoint or parameter lookups that return undefined at runtime; TypeScript optional chaining (`resource?.endpoint`) silently yielding undefined; object destructuring where the property does not exist; passing a variable before it is assigned.

Related errors


AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16). Data as JSON: /api/errors/642d09ee859e4a60. Report an issue: GitHub.

Appendix: source

Thrown at src/Aspire.Hosting.CodeGeneration.TypeScript/Resources/base.mts:261

    if (typeof matchValueOrWhenTrue === 'string') {
        return new ReferenceExpression(condition, matchValueOrWhenTrue, whenTrueOrWhenFalse, whenFalse!);
    }

    return new ReferenceExpression(condition, 'True', matchValueOrWhenTrue, whenTrueOrWhenFalse);
}

registerHandleWrapper('Aspire.Hosting/Aspire.Hosting.ApplicationModel.ReferenceExpression', (handle, client) =>
    new ReferenceExpression(handle, client)
);

/**
 * Extracts a value for use in reference expressions.
 * Supports handles (objects) and string literals.
 * @internal
 */
function extractHandleForExpr(value: unknown): unknown {
    if (value === null || value === undefined) {
        throw new Error('Cannot use null or undefined in reference expression');
    }

    // String literals - include directly in the expression
    if (typeof value === 'string') {
        return value;
    }

    // Number literals - convert to string
    if (typeof value === 'number') {
        return String(value);
    }

    // Handle objects - get their JSON representation
    if (isHandleLike(value)) {
        return value.toJSON();
    }

    // Objects with marshalled expression/handle payloads

View on GitHub (pinned to 25830f84bd)