Skip to content

fix(s3): use EmulatorConfig for FLOCI_HOSTNAME to fix native image crash#4

Open
Meemaw wants to merge 1 commit intomainfrom
fix/s3-virtual-host-emulator-config
Open

fix(s3): use EmulatorConfig for FLOCI_HOSTNAME to fix native image crash#4
Meemaw wants to merge 1 commit intomainfrom
fix/s3-virtual-host-emulator-config

Conversation

@Meemaw
Copy link
Copy Markdown
Member

@Meemaw Meemaw commented Apr 8, 2026

S3VirtualHostFilter used @ConfigProperty injection in its constructor, which gets baked into the GraalVM native binary at build time. Setting FLOCI_HOSTNAME at runtime via Docker env var caused an IllegalStateException because the runtime value differed from the build-time value (null).

Refactor to inject EmulatorConfig (which uses @ConfigMapping and is runtime-safe) instead of raw @ConfigProperty, following the established pattern used by StorageFactory, ServiceRegistry, RegionResolver, etc.

Also make bucket extraction hostname-aware: only treat the first label as a bucket name when the remainder matches the configured base hostname (or a well-known AWS S3 domain). This prevents false positives when Floci sits behind a multi-label hostname like floci.svc.cluster.local.

Summary

Fixes native image crash when FLOCI_HOSTNAME is set at runtime, and prevents false-positive virtual-host bucket extraction in multi-label hostname environments (e.g. Kubernetes).

Based on #3

Reproduction:

$ docker run -e FLOCI_HOSTNAME=floci hectorvent/floci:1.4.0

2026-04-08 12:25:15,330 ERROR [io.quarkus.runtime.Application] (main) Failed to start application: java.lang.RuntimeException: Failed to start quarkus
    at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
    at io.quarkus.runtime.Application.start(Application.java:112)
    at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:127)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:79)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:50)
    at io.quarkus.runtime.Quarkus.run(Quarkus.java:143)
    at io.quarkus.runner.GeneratedMain.main(Unknown Source)
Caused by: java.lang.IllegalStateException: A runtime config property value differs from the value that was injected during the static intialization phase:
 - the runtime value of 'floci.hostname' is [floci] but the value [null] was injected into io.github.hectorvent.floci.services.s3.S3VirtualHostFilter()

If that's intentional then annotate the injected field/parameter with @io.quarkus.runtime.annotations.StaticInitSafe to eliminate the false positive.
    at io.quarkus.arc.runtime.ConfigStaticInitValues.onStart(ConfigStaticInitValues.java:61)
    at io.quarkus.arc.runtime.ConfigStaticInitValues_Observer_onStart_fdhd3Q2CPu5KfpwUMYn5Ol6axJU.notify(Unknown Source)
    at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:366)
    at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:348)
    at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:81)
    at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:165)
    at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:115)
    at io.quarkus.runner.recorded.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
    at io.quarkus.runner.recorded.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
    ... 7 more

Type of change

  • Bug fix (fix:)
  • New feature (feat:)
  • Breaking change (feat!: or fix!:)
  • Docs / chore

AWS Compatibility

Incorrect behavior: FLOCI_HOSTNAME env var crashes the native image on startup. Without it, virtual-host bucket extraction has no hostname awareness, causing false positives in Docker Compose / Kubernetes setups.

Checklist

  • ./mvnw test passes locally
  • New or updated integration test added
  • Commit messages follow Conventional Commits

Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 1 additional finding.

Open in Devin Review

@Meemaw Meemaw force-pushed the fix/s3-virtual-host-emulator-config branch 2 times, most recently from 813a367 to 978e5bf Compare April 8, 2026 14:40
…tFilter

Replace @ConfigProperty constructor injection with programmatic
ConfigProvider.getConfig() lookup to fix native image crash when
FLOCI_HOSTNAME is set at runtime. @PreMatching JAX-RS filters run
before CDI beans are fully initialized, so neither @ConfigProperty
nor @ConfigMapping beans are available during filter construction.

Also make bucket extraction hostname-aware: only treat the first label
as a bucket name when the remainder matches the configured base hostname
(or a well-known AWS S3 domain). This prevents false positives when
Floci sits behind a multi-label hostname like floci.svc.cluster.local.
@Meemaw Meemaw force-pushed the fix/s3-virtual-host-emulator-config branch from 978e5bf to ef5c36d Compare April 8, 2026 14:40
Copy link
Copy Markdown

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

View 3 additional findings in Devin Review.

Open in Devin Review

Comment on lines +19 to +25
public S3VirtualHostFilter() {
var config = ConfigProvider.getConfig();
String baseUrl = config
.getOptionalValue("floci.base-url", String.class)
.orElse("http://localhost:4566");
Optional<String> hostname = config
.getOptionalValue("floci.hostname", String.class);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 Violation of AGENT.md "Use constructor injection" rule: replaces @Inject with manual ConfigProvider

The PR removes @Inject constructor injection and replaces it with ConfigProvider.getConfig(), directly violating the mandatory AGENT.md Code Style rule at line 268: "Use constructor injection". This is the only file in the entire codebase that uses ConfigProvider.getConfig() — every other class that needs configuration uses CDI injection (typically via EmulatorConfig or @ConfigProperty), as seen in ServiceEnabledFilter.java:29-32, PreSignedUrlFilter.java:16-19, AwsJsonMessageBodyWriter.java:15-18, and dozens of service classes. This also violates the AGENT.md rule "Follow existing project patterns" (line 272).

Prompt for agents
The S3VirtualHostFilter constructor was changed from CDI constructor injection (@Inject + @ConfigProperty) to manual ConfigProvider.getConfig() usage. This violates the AGENT.md mandatory rules: 'Use constructor injection' and 'Follow existing project patterns'.

The entire rest of the codebase uses CDI injection for configuration, either via EmulatorConfig (the type-safe config interface) or @ConfigProperty annotations. This is the only class using ConfigProvider directly.

To fix this, restore the @Inject-based constructor injection. The original approach was:

@Inject
public S3VirtualHostFilter(
        @ConfigProperty(name = "floci.base-url", defaultValue = "http://localhost:4566") String baseUrl,
        @ConfigProperty(name = "floci.hostname") Optional<String> hostname) {
    // ... same body
}

Alternatively, consider injecting EmulatorConfig instead of individual @ConfigProperty values, which is the more common pattern in this codebase (used by S3Service, LambdaService, etc.).

If there was a genuine technical issue with CDI injection in @PreMatching filters, it should be documented and an exception to the rule should be noted in a code comment.
Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant