anomalyco/sst · error · VisibleError

Cannot access `nodes.service` in dev mode.

Error message

Cannot access `nodes.service` in dev mode.

What it means

In SST's `Service` (v1) component, the `nodes` accessor object exposes raw Pulumi resources. During `sst dev`, the service runs as a live Lambda/container and the underlying `ecs.Service` Pulumi resource is not created, so `nodes.service` would be `undefined`. SST throws this `VisibleError` up front to give a clear message instead of a cryptic null dereference.

Source

Thrown at platform/src/components/aws/service-v1.ts:810

      return this.devUrl;
    }

    if (!this._url) throw new VisibleError(errorMessage);
    return this._url;
  }

  /**
   * The underlying [resources](/docs/components/#nodes) this component creates.
   */
  public get nodes() {
    const self = this;
    return {
      /**
       * The Amazon ECS Service.
       */
      get service() {
        if ($dev)
          throw new VisibleError("Cannot access `nodes.service` in dev mode.");
        return self.service!;
      },
      /**
       * The Amazon ECS Task Role.
       */
      get taskRole() {
        return self.taskRole;
      },
      /**
       * The Amazon ECS Task Definition.
       */
      get taskDefinition() {
        if ($dev)
          throw new VisibleError(
            "Cannot access `nodes.taskDefinition` in dev mode.",
          );
        return self.taskDefinition!;
      },

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Wrap the `nodes.service` access in `if (!$dev) { ... }` so it only runs on deploy.
  2. Use the dev-mode alternatives the component provides (e.g. dev URL from `service.url`) instead of the raw resource.
  3. Split infrastructure references into a module only imported/executed at deploy time.
  4. If the reference is genuinely needed in dev, run `sst deploy --stage dev` instead of `sst dev` for that stack.

Example fix

// before
const svc = myService.nodes.service;
svc.name.apply((n) => grantAccess(n));

// after
if (!$dev) {
  const svc = myService.nodes.service;
  svc.name.apply((n) => grantAccess(n));
}
Defensive patterns

Strategy: validation

Validate before calling

if ($dev) {
  // skip nodes.service usage in dev
} else {
  const svc = myService.nodes.service;
}

Type guard

function canAccessNodes<T>(component: T): boolean {
  return !($dev as boolean);
}

Try / catch

try {
  const svc = myService.nodes.service;
} catch (e) {
  if (e instanceof VisibleError && e.message.includes("dev mode")) return null;
  throw e;
}

Prevention

When it happens

Trigger: Calling `service.nodes.service` while running `sst dev` (i.e. `$dev` is true). Any code path that reads the ECS Service resource from the nodes getter during the dev loop triggers it.

Common situations: Developers wiring an ECS Service to another component (e.g. granting IAM permissions or referencing the service ARN) in code that also runs during dev mode; following examples/docs that use `nodes` without dev-mode guards.

Related errors


AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30). Data as JSON: /api/errors/7fdd240493f301b7. Report an issue: GitHub.