floci-io/floci · error · RuntimeException

Failed to fetch CloudFormation template from ${url}: ${e.get

Error message

Failed to fetch CloudFormation template from ${url}: ${e.getMessage()}

What it means

Thrown when CloudFormation cannot fetch a template specified via TemplateURL. Floci only resolves TemplateURL against its own S3 emulator (path-style or virtual-hosted-style URLs on the configured hostname); the fetched object is read with s3Service.getObject(bucket, key). Any failure (missing bucket/object, wrong host, unreadable content) is wrapped in a RuntimeException with the URL and the underlying message.

Source

Thrown at src/main/java/io/github/hectorvent/floci/services/cloudformation/CloudFormationService.java:1357

                || host.endsWith(".localhost"));

        if (isVirtualHosted) {
            bucket = host.split("\\.")[0];
            key = path.startsWith("/") ? path.substring(1) : path;
        } else {
            // Path-style: /bucket/key
            String rawPath = path.startsWith("/") ? path.substring(1) : path;
            int slash = rawPath.indexOf('/');
            bucket = slash > 0 ? rawPath.substring(0, slash) : rawPath;
            key = slash > 0 ? rawPath.substring(slash + 1) : "";
        }

        try {
            var obj = s3Service.getObject(bucket, key);
            return new String(obj.getData());
        } catch (Exception e) {
            LOG.errorv("Failed to fetch CloudFormation template from {0}: {1}", url, e.getMessage());
            throw new RuntimeException("Failed to fetch CloudFormation template from " + url + ": " + e.getMessage(), e);
        }
    }

    private boolean isConfiguredVirtualHostedS3Host(String host) {
        String suffix = config.hostname().orElse(EmbeddedDnsServer.DEFAULT_SUFFIX);
        return hasBucketPrefixForSuffix(host, suffix);
    }

    private static boolean hasBucketPrefixForSuffix(String host, String suffix) {
        if (host == null || suffix == null || suffix.isBlank()) {
            return false;
        }
        String normalizedHost = host.toLowerCase(Locale.ROOT);
        String normalizedSuffix = suffix.toLowerCase(Locale.ROOT);
        return normalizedHost.length() > normalizedSuffix.length() + 1
                && normalizedHost.endsWith("." + normalizedSuffix);
    }

View on GitHub (pinned to 62ff490619)

Solutions

  1. Verify the object exists in the emulator: aws --endpoint-url http://localhost:4566 s3 ls s3://<bucket>/<key> (run against Floci, not real AWS).
  2. Use a path-style URL against the emulator, e.g. http://localhost:4566/<bucket>/<key>, to rule out virtual-hosted hostname resolution issues.
  3. If you must use virtual-hosted style, confirm floci hostname config and that the embedded DNS server resolves <bucket>.<suffix> to the emulator.
  4. If the bucket was created in a previous run, check the storage mode (memory vs persistent) — a memory backend loses objects on restart; re-upload the template.

Example fix

# before
aws --endpoint-url http://localhost:4566 cloudformation create-stack \
  --stack-name s --template-url https://my-bucket.s3.amazonaws.com/template.yml

# after
aws --endpoint-url http://localhost:4566 s3 cp template.yml s3://my-bucket/template.yml
aws --endpoint-url http://localhost:4566 cloudformation create-stack \
  --stack-name s --template-url http://localhost:4566/my-bucket/template.yml
Defensive patterns

Strategy: validation

Validate before calling

// Before CreateStack with TemplateURL, confirm the object is readable in the emulator
var obj = s3.getObject(b -> b.bucket(bucket).key(key)); // throws NoSuchKey if absent
// and build a path-style URL the emulator definitely serves:
String templateUrl = "http://localhost:4566/" + bucket + "/" + key;

Try / catch

catch (RuntimeException e) when creating the stack; inspect the message for "Failed to fetch CloudFormation template" and surface the underlying S3 cause (usually NoSuchKey) to the user instead of retrying — retrying without fixing the URL/object cannot succeed.

Prevention

When it happens

Trigger: CreateStack / UpdateStack / CreateStackSet called with TemplateURL pointing at an S3 object that does not exist in the emulator's S3 storage, a URL whose host is not the emulator hostname (real S3, localhost with wrong port, https vs http mismatch), or a virtual-hosted-style URL whose suffix does not match floci hostname config.

Common situations: Templates written for real AWS (https://bucket.s3.amazonaws.com/key), S3 buckets created before persistence was enabled so the object is gone after restart, DNS/hostname misconfiguration where virtual-hosted-style URLs never match EmbeddedDnsServer.DEFAULT_SUFFIX, or a typo in the bucket/key path.

Related errors


AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14). Data as JSON: /api/errors/9a80b2eff3c7d00e. Report an issue: GitHub.