anomalyco/sst · error · PublishError

Failed to publish event to bus

Error message

Failed to publish event to bus

What it means

`bus.publish` sends an event to Amazon EventBridge via the PutEvents API using awsFetch. If the HTTP response is not OK (e.g. 4xx/5xx from EventBridge or a signing/network failure at the fetch level surfaced by awsFetch), a `PublishError` is thrown with the message "Failed to publish event to bus"; the original `Response` is attached to the error as `error.response` for inspecting the AWS error body.

Source

Thrown at sdk/js/src/aws/bus.ts:80

            {
              Source: [Resource.App.name, Resource.App.stage].join("."),
              DetailType: evt.type,
              Detail: JSON.stringify({
                metadata: evt.metadata,
                properties: evt.properties,
              }),
              EventBusName: typeof name === "string" ? name : name.name,
            },
          ],
        }),
      },
      options,
    )
      .catch((e) => {
        if (e instanceof Error) console.log("cause", e.cause);
        throw e;
      });
    if (!res.ok) throw new PublishError(res);
    return res.json();
  }

  export class PublishError extends Error {
    constructor(public readonly response: Response) {
      super("Failed to publish event to bus");
    }
  }
}

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Inspect `error.response` and read the response body for the exact AWS error code (AccessDeniedException, ResourceNotFoundException, etc.).
  2. Grant the publishing function's IAM role `events:PutEvents` on the target event bus, and link the bus resource to the function.
  3. Verify the bus name/resource passed to publish exists in the current stage.
  4. Reduce event size below 256KB if the payload is large, then retry with backoff for throttling errors.

Example fix

try {
  await bus.publish(Resource.MyBus, event);
} catch (e) {
  if (e instanceof bus.PublishError) {
    const detail = await e.response.text();
    console.error("PutEvents failed:", e.response.status, detail);
  }
}
Defensive patterns

Strategy: retry

Validate before calling

import { Resource } from "sst";
if (!Resource[busName]) throw new Error(`Bus ${busName} is not linked to this function`);

Type guard

function isPublishError(e: unknown): e is bus.PublishError {
  return e instanceof bus.PublishError && typeof e.response === "object";
}

Try / catch

for (let attempt = 0; attempt < 3; attempt++) {
  try {
    return await bus.publish(Resource.MyBus, event);
  } catch (e) {
    if (e instanceof bus.PublishError && e.response.status < 500) throw e;
    await new Promise(r => setTimeout(r, 2 ** attempt * 100));
  }
}
throw new Error("Publish failed after retries");

Prevention

When it happens

Trigger: Any `bus.publish(...)` call where the EventBridge PutEvents request returns a non-OK HTTP status: invalid event bus name, missing IAM `events:PutEvents` permission for the function's role, event detail exceeding size limits, or AWS throttling/errors.

Common situations: Function's IAM role lacks PutEvents on the bus; publishing to a bus that was renamed or removed across stages; `Resource` app name/stage mismatch causing wrong bus ARN; oversized event payloads (EventBridge 256KB limit); local dev without AWS credentials (see client error).

Related errors


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