denoland/deno · error · NodeTypeError

ERR_INVALID_OBJECT_DEFINE_PROPERTY

ERR_INVALID_OBJECT_DEFINE_PROPERTY

Error message

'process.env' does not accept an accessor(getter/setter) descriptor

What it means

The defineProperty trap of the process.env Proxy rejects accessor descriptors: any attributes object containing get or set throws ERR_INVALID_OBJECT_DEFINE_PROPERTY with the 'does not accept an accessor(getter/setter) descriptor' message. process.env is backed by real OS environment strings, so per-variable getter/setter semantics cannot be represented.

Source

Thrown at ext/node/polyfills/_process/process.ts:182

      }

      return typeof denoEnvGet(prop) === "string";
    },
    deleteProperty(target, key) {
      if (typeof key === "symbol") {
        delete target[key];
        return true;
      }

      Deno.env.delete(String(key));
      return true;
    },
    defineProperty(target, property, attributes) {
      if (
        ObjectHasOwn(attributes, "get") ||
        ObjectHasOwn(attributes, "set")
      ) {
        throw new ERR_INVALID_OBJECT_DEFINE_PROPERTY(
          "'process.env' does not accept an " +
            "accessor(getter/setter) descriptor",
        );
      }

      if (
        !attributes?.configurable || !attributes?.enumerable ||
        !attributes?.writable
      ) {
        throw new ERR_INVALID_OBJECT_DEFINE_PROPERTY(
          "'process.env' only accepts a " +
            "configurable, writable," +
            " and enumerable data descriptor",
        );
      }

      if (typeof property === "symbol") {
        ReflectDefineProperty(target, property, {

View on GitHub (pinned to 89f33cbef2)

Solutions

  1. Use plain assignment instead: process.env.K = 'v'
  2. Wrap env access in your own config object if you need getters/computed values
  3. In tests, save the old value, assign, and restore afterwards rather than redefining
  4. Delete with delete process.env.K during cleanup

Example fix

// before
Object.defineProperty(process.env, 'NODE_ENV', {
  get: () => 'test',
  configurable: true,
}); // throws

// after
process.env.NODE_ENV = 'test';
Defensive patterns

Strategy: validation

Validate before calling

function isAccessorDescriptor(attrs) {
  return !!attrs && ('get' in attrs || 'set' in attrs);
}
if (isAccessorDescriptor(desc)) {
  process.env[key] = String(desc.value ?? ''); // use assignment instead
} else {
  Object.defineProperty(process.env, key, desc);
}

Try / catch

try {
  Object.defineProperty(process.env, k, desc);
} catch (e) {
  if (e.code === 'ERR_INVALID_OBJECT_DEFINE_PROPERTY') {
    process.env[k] = String(desc.value);
  } else throw e;
}

Prevention

When it happens

Trigger: Object.defineProperty(process.env, 'K', { get() {...}, set(v) {...} }); test spies/stubs that redefine env properties via defineProperty; frameworks trying to make env reads observable or reactive.

Common situations: Test tooling stubbing env vars (sinon-style); reactive-config libraries wrapping env in accessors; porting browser-style observable patterns onto process.env.

Related errors


AI-assisted analysis of denoland/deno@89f33cbef2 (2026-08-16). Data as JSON: /api/errors/3a0a529053d177c6. Report an issue: GitHub.