clockworklabs/SpacetimeDB · error · TypeError

Environment ' ' needs a nonempty literal union

Error message

Environment '${name}' needs a nonempty literal union

What it means

An environment enum must expose at least one variant and all variant names must be distinct, because the set of names becomes the allowed literal union for the variable. An empty variant list or duplicate names would produce an empty or ambiguous union, so it is rejected.

Solutions

  1. Add at least one variant to the enum
  2. Ensure all variant names are unique
  3. Deduplicate names before constructing the type

Example fix

// before
enum Flags { On, On } // duplicate
// after
enum Flags { On, Off }
Defensive patterns

Strategy: validation

Validate before calling

function assertDistinctNonemptyVariants(ty) {
  const names = ty.algebraicType.value.variants.map(v => v.name);
  if (names.length === 0 || new Set(names).size !== names.length) {
    throw new TypeError('Enum must have a nonempty, distinct set of variant names');
  }
}

Type guard

const isNonemptyDistinctUnion = (names: string[]): boolean => names.length > 0 && new Set(names).size === names.length;

Try / catch

try {
  environmentDeclarations(schema);
} catch (e) {
  if (e instanceof TypeError && /nonempty literal union/.test(e.message)) {
    console.error('Enum for env var is empty or has duplicate cases');
  } else throw e;
}

Prevention

When it happens

Trigger: Building an enum with zero variants, or an enum with two variants sharing the same name, then declaring it as an environment variable.

Common situations: Programmatically generating variant lists where an empty filter yields no cases; duplicated case names from string concatenation in generated code.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of clockworklabs/SpacetimeDB@eddf9f5014 (2026-09-20). Data as JSON: /api/errors/b78e271ca4b01877. Report an issue: GitHub.

Appendix: source

Thrown at crates/bindings-typescript/src/server/environment.ts:81

      const values = type.value.variants.map(variant => {
        if (
          variant.algebraicType.tag !== 'Product' ||
          variant.algebraicType.value.elements.length !== 0
        ) {
          throw new TypeError(
            `Environment '${name}' cannot use an enum payload`
          );
        }
        if (typeof variant.name !== 'string')
          throw new TypeError(
            `Environment '${name}' enum cases must have names`
          );
        if (bytes.encode(variant.name).length > MAX_ENV_VALUE_BYTES)
          throw new TypeError(`Environment '${name}' literal is too long`);
        return variant.name;
      });
      if (values.length === 0 || new Set(values).size !== values.length)
        throw new TypeError(
          `Environment '${name}' needs a nonempty literal union`
        );
      ty =
        values.length === 1
          ? { tag: 'StringLiteral', value: values[0]! }
          : { tag: 'Union', value: values };
    }
    return { name, ty, optional };
  });
}

View on GitHub (pinned to eddf9f5014)