anomalyco/sst · warning · VisibleError

sst.aws.linkable is deprecated. Use sst.Linkable.wrap instea

Error message

sst.aws.linkable is deprecated. Use sst.Linkable.wrap instead.
sst.Linkable.wrap(MyResource, (resource) => ({
  properties: { ... },
  with: [
    sst.aws.permission({ actions: ["foo:*"], resources: [resource.arn] })
  ]
}))

What it means

sst.aws.linkable() was the old way to register a custom resource class as linkable in SST. It has been removed and now unconditionally throws a VisibleError directing you to the replacement API, sst.Linkable.wrap, which supports richer properties and permission attachments.

Source

Thrown at platform/src/components/aws/linkable.ts:21

export const URL_UNAVAILABLE = "http://url-unavailable-in-dev.mode";

/** @deprecated
 * instead try
 * ```
 * sst.Linkable.wrap(MyResource, (resource) => ({
 *   properties: { ... },
 *   with: [
 *     sst.aws.permission({ actions: ["foo:*"], resources: [resource.arn] })
 *   ]
 * }))
 * ```
 */
export function linkable<T>(
  obj: { new (...args: any[]): T },
  cb: (resource: T) => FunctionPermissionArgs[],
) {
  throw new VisibleError(
    [
      "sst.aws.linkable is deprecated. Use sst.Linkable.wrap instead.",
      "sst.Linkable.wrap(MyResource, (resource) => ({",
      "  properties: { ... },",
      "  with: [",
      '    sst.aws.permission({ actions: ["foo:*"], resources: [resource.arn] })',
      "  ]",
      "}))",
    ].join("\n"),
  );
}

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Replace sst.aws.linkable with sst.Linkable.wrap, passing the resource class and a callback returning { properties, with }
  2. Convert the returned FunctionPermissionArgs array into the `with: [sst.aws.permission({ actions, resources })]` shape
  3. Remove any imports of sst.aws.linkable and re-run the deploy

Example fix

// before
sst.aws.linkable(MyResource, (resource) => [
  { actions: ["foo:*"], resources: [resource.arn] }
]);
// after
sst.Linkable.wrap(MyResource, (resource) => ({
  properties: { arn: resource.arn },
  with: [
    sst.aws.permission({ actions: ["foo:*"], resources: [resource.arn] })
  ]
}));
Defensive patterns

Strategy: validation

Validate before calling

// Guard before registering linkability
if ("linkable" in sst.aws) {
  throw new Error("sst.aws.linkable is removed; use sst.Linkable.wrap");
}

Type guard

function usesLegacyLinkable(api: unknown): api is { linkable: Function } {
  return typeof api === "object" && api !== null && "linkable" in api;
}

Try / catch

try {
  registerLinkable();
} catch (e) {
  if (String(e).includes("Linkable.wrap")) {
    console.error("Migrate registration to sst.Linkable.wrap");
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling sst.aws.linkable(MyResource, (resource) => [...]) inside a component definition or a .linkable() registration file, typically after upgrading SST from v2 to v3+ where the API was replaced.

Common situations: Upgrading an SST v2 project to v3 and keeping the old linkable.ts registration file; copying a legacy custom-resource example from old docs or blog posts.

Related errors


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