anomalyco/sst · error · VisibleError

Copy destination path "${to}" must be relative

Error message

Copy destination path "${to}" must be relative

What it means

normalizeCopyFiles() validates the `copyFiles` option of SST Functions. The destination path (`to`, defaulting to `from`) is joined into the bundle, so absolute paths make no sense and are rejected with this VisibleError.

Source

Thrown at platform/src/components/aws/function.ts:2019

                  maxAge: url.cors.maxAge && toSeconds(url.cors.maxAge),
                };

        return {
          authorization,
          cors,
          route: normalizeRouteArgs(url.router, url.route),
        };
      });
    }

    function normalizeCopyFiles() {
      return output(args.copyFiles ?? []).apply((copyFiles) =>
        Promise.all(
          copyFiles.map(async (entry) => {
            const from = path.join($cli.paths.root, entry.from);
            const to = entry.to || entry.from;
            if (path.isAbsolute(to)) {
              throw new VisibleError(
                `Copy destination path "${to}" must be relative`,
              );
            }

            const stats = await fs.promises.stat(from);
            const isDir = stats.isDirectory();

            return { from, to, isDir };
          }),
        ),
      );
    }

    function normalizeVpc() {
      // "vpc" is undefined
      if (!args.vpc) return;

      // "vpc" is a Vpc component

View on GitHub (pinned to a0bd20f762)

Solutions

  1. Change `to` to a path relative to the bundle root, e.g. "config/config.json"
  2. Also make `from` (and thus the defaulted `to`) relative to the app root if it was absolute

Example fix

// before
copyFiles: [{ from: "config/app.json", to: "/etc/app/app.json" }]
// after
copyFiles: [{ from: "config/app.json", to: "config/app.json" }]
Defensive patterns

Strategy: validation

Validate before calling

import path from "path";
for (const f of args.copyFiles ?? []) {
  const to = f.to || f.from;
  if (path.isAbsolute(to)) throw new Error(`copyFiles 'to' must be relative: ${to}`);
}

Type guard

const isRelativeCopy = (f: { from: string; to?: string }) =>
  !path.isAbsolute(f.to || f.from);

Try / catch

try {
  const fn = new sst.aws.Function("Fn", { copyFiles });
} catch (e) {
  if ((e as Error).message.includes("must be relative")) {
    console.error("Use bundle-relative paths for copyFiles destinations");
  }
  throw e;
}

Prevention

When it happens

Trigger: Passing copyFiles: [{ from: "config/x.json", to: "/etc/app/config.json" }] — an absolute `to` path; `entry.to` empty and `entry.from` absolute.

Common situations: Reusing OS-absolute destination paths from Docker or server configs inside Lambda bundle copy rules; building paths with path.resolve() instead of relative strings.

Related errors


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