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
- Inspect `error.response` and read the response body for the exact AWS error code (AccessDeniedException, ResourceNotFoundException, etc.).
- Grant the publishing function's IAM role `events:PutEvents` on the target event bus, and link the bus resource to the function.
- Verify the bus name/resource passed to publish exists in the current stage.
- 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
- Link the bus resource to publishing functions so IAM permissions are generated automatically.
- Keep event payloads under the 256KB EventBridge limit.
- Check `e.response.status` to distinguish retryable (5xx/throttling) from permanent (4xx) errors.
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
- Failed to describe task
- Failed to run task
- Failed to stop task
- Bastion instance profile must be a name, not an ARN.
- failed to delete SSM parameter %s: %w
AI-assisted analysis of anomalyco/sst@a0bd20f762 (2026-08-30).
Data as JSON: /api/errors/d6897d96ad4c1f49.
Report an issue: GitHub.