{"record":{"id":"9a80b2eff3c7d00e","repo":"floci-io/floci","slug":"failed-to-fetch-cloudformation-template-from-url","errorCode":null,"errorMessage":"Failed to fetch CloudFormation template from ${url}: ${e.getMessage()}","messagePattern":"Failed to fetch CloudFormation template from (.+?): (.+?)","errorType":"exception","errorClass":"RuntimeException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/services/cloudformation/CloudFormationService.java","lineNumber":1357,"sourceCode":"                || host.endsWith(\".localhost\"));\n\n        if (isVirtualHosted) {\n            bucket = host.split(\"\\\\.\")[0];\n            key = path.startsWith(\"/\") ? path.substring(1) : path;\n        } else {\n            // Path-style: /bucket/key\n            String rawPath = path.startsWith(\"/\") ? path.substring(1) : path;\n            int slash = rawPath.indexOf('/');\n            bucket = slash > 0 ? rawPath.substring(0, slash) : rawPath;\n            key = slash > 0 ? rawPath.substring(slash + 1) : \"\";\n        }\n\n        try {\n            var obj = s3Service.getObject(bucket, key);\n            return new String(obj.getData());\n        } catch (Exception e) {\n            LOG.errorv(\"Failed to fetch CloudFormation template from {0}: {1}\", url, e.getMessage());\n            throw new RuntimeException(\"Failed to fetch CloudFormation template from \" + url + \": \" + e.getMessage(), e);\n        }\n    }\n\n    private boolean isConfiguredVirtualHostedS3Host(String host) {\n        String suffix = config.hostname().orElse(EmbeddedDnsServer.DEFAULT_SUFFIX);\n        return hasBucketPrefixForSuffix(host, suffix);\n    }\n\n    private static boolean hasBucketPrefixForSuffix(String host, String suffix) {\n        if (host == null || suffix == null || suffix.isBlank()) {\n            return false;\n        }\n        String normalizedHost = host.toLowerCase(Locale.ROOT);\n        String normalizedSuffix = suffix.toLowerCase(Locale.ROOT);\n        return normalizedHost.length() > normalizedSuffix.length() + 1\n                && normalizedHost.endsWith(\".\" + normalizedSuffix);\n    }\n","sourceCodeStart":1339,"sourceCodeEnd":1375,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/services/cloudformation/CloudFormationService.java#L1339-L1375","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Verify the object exists in the emulator: aws --endpoint-url http://localhost:4566 s3 ls s3://<bucket>/<key> (run against Floci, not real AWS).","Use a path-style URL against the emulator, e.g. http://localhost:4566/<bucket>/<key>, to rule out virtual-hosted hostname resolution issues.","If you must use virtual-hosted style, confirm floci hostname config and that the embedded DNS server resolves <bucket>.<suffix> to the emulator.","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."],"exampleFix":"# before\naws --endpoint-url http://localhost:4566 cloudformation create-stack \\\n  --stack-name s --template-url https://my-bucket.s3.amazonaws.com/template.yml\n\n# after\naws --endpoint-url http://localhost:4566 s3 cp template.yml s3://my-bucket/template.yml\naws --endpoint-url http://localhost:4566 cloudformation create-stack \\\n  --stack-name s --template-url http://localhost:4566/my-bucket/template.yml","handlingStrategy":"validation","validationCode":"// Before CreateStack with TemplateURL, confirm the object is readable in the emulator\nvar obj = s3.getObject(b -> b.bucket(bucket).key(key)); // throws NoSuchKey if absent\n// and build a path-style URL the emulator definitely serves:\nString templateUrl = \"http://localhost:4566/\" + bucket + \"/\" + key;","typeGuard":null,"tryCatchPattern":"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.","preventionTips":["Upload the template to the emulator's S3 before referencing it","Prefer path-style URLs (http://localhost:4566/bucket/key) over virtual-hosted style in emulator tests","Run template upload and stack create in the same script so the object is guaranteed present"],"tags":["cloudformation","s3","template-url","floci"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}