{"record":{"id":"b7810bc1566f687b","repo":"floci-io/floci","slug":"tls-enabled-but-no-certificate-provided-and-self-s","errorCode":null,"errorMessage":"TLS enabled but no certificate provided and self-signed generation disabled. Set FLOCI_TLS_CERT_PATH + FLOCI_TLS_KEY_PATH, or enable FLOCI_TLS_SELF_SIGNED.","messagePattern":"TLS enabled but no certificate provided and self-signed generation disabled\\. Set FLOCI_TLS_CERT_PATH \\+ FLOCI_TLS_KEY_PATH, or enable FLOCI_TLS_SELF_SIGNED\\.","errorType":"console","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"src/main/java/io/github/hectorvent/floci/config/TlsConfigSource.java","lineNumber":114,"sourceCode":"                \n                // Regenerate when the hostname config changed, or when the existing certificate\n                // is a legacy non-self-signed cert (issuer != subject) — those cannot serve as a\n                // trust anchor for clients that install them, so an upgrade must replace them.\n                if (hostnameConfigChanged(tlsDir, currentHostnames) || !isSelfSigned(certFile)) {\n                    generateSelfSignedCert(tlsDir, certFile, keyFile);\n                } else {\n                    // Configuration unchanged - reuse existing certificate\n                    LOG.infov(\"TLS: reusing existing self-signed certificate: {0}\", certFile);\n                }\n            } else {\n                // Certificate files don't exist - generate new certificate\n                generateSelfSignedCert(tlsDir, certFile, keyFile);\n            }\n\n            certPath = certFile.toAbsolutePath().toString();\n            keyPath = keyFile.toAbsolutePath().toString();\n        } else {\n            throw new IllegalStateException(\n                    \"TLS enabled but no certificate provided and self-signed generation disabled. \"\n                            + \"Set FLOCI_TLS_CERT_PATH + FLOCI_TLS_KEY_PATH, or enable FLOCI_TLS_SELF_SIGNED.\");\n        }\n\n        properties.put(\"quarkus.http.ssl.certificate.files\", certPath);\n        properties.put(\"quarkus.http.ssl.certificate.key-files\", keyPath);\n        // When TLS is enabled, Quarkus HTTP and HTTPS run on internal ports.\n        // A TlsProxyServer (NetServer) listens on the public Floci port (4566)\n        // and does protocol detection to route HTTP and HTTPS to the correct backend.\n        properties.put(\"quarkus.http.insecure-requests\", \"enabled\");\n        properties.put(\"quarkus.http.host\", \"127.0.0.1\");\n        properties.put(\"quarkus.http.port\", \"4510\");\n        properties.put(\"quarkus.http.ssl-port\", \"4511\");\n\n        LOG.infov(\"TLS: HTTPS enabled — proxy will listen on port {0} (HTTP+HTTPS), cert={1}\",\n                resolveProperty(\"floci.port\", \"4566\"), certPath);\n    }\n","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/floci-io/floci/blob/62ff490619e7bd3554597c28c704081b4c15add5/src/main/java/io/github/hectorvent/floci/config/TlsConfigSource.java#L96-L132","documentation":"Thrown by PollForJobs when the actionTypeId.owner field in the request is not 'Custom' (or, for PollForThirdPartyJobs, not 'ThirdParty'). The emulator only queues custom-job polling for the matching owner category, mirroring AWS CodePipeline's rule that PollForJobs is reserved for Custom actions and PollForThirdPartyJobs for ThirdParty actions. The check happens before any job lookup, so the request fails fast with HTTP 400 ValidationException.","triggerScenarios":"Calling PollForJobs with actionTypeId.owner = 'AWS' or 'ThirdParty'; calling PollForThirdPartyJobs with owner = 'Custom' or 'AWS'; omitting the owner field entirely (path('owner').asText() returns \"\" which fails the equals check).","commonSituations":"A custom worker built for one action type pointed at the wrong poll endpoint; copy-pasting an actionTypeId from a pipeline that uses an AWS-managed provider; SDK models where owner defaults to something other than Custom.","solutions":["Set actionTypeId.owner to 'Custom' when calling PollForJobs (and 'ThirdParty' for PollForThirdPartyJobs)","Verify the category/provider/version triple also matches the ActionType you registered via PutActionType, since owner is only one part of the key","Check the worker's configuration for which poll operation it invokes and align it with the owner your action declaration uses"],"exampleFix":"// before\nActionTypeId id = ActionTypeId.builder().category(ActionCategory.Deploy).owner(\"AWS\").provider(\"MyProvider\").version(\"1\").build();\npoller.pollForJobs(PollForJobsRequest.builder().actionTypeId(id).build());\n\n// after\nActionTypeId id = ActionTypeId.builder().category(ActionCategory.Deploy).owner(\"Custom\").provider(\"MyProvider\").version(\"1\").build();\npoller.pollForJobs(PollForJobsRequest.builder().actionTypeId(id).build());","handlingStrategy":"validation","validationCode":"String owner = request.actionTypeId().owner();\nString expected = thirdParty ? \"ThirdParty\" : \"Custom\";\nif (!expected.equals(owner)) {\n    throw new IllegalArgumentException(\"PollForJobs owner must be \" + expected + \", got: \" + owner);\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Centralize the ActionTypeId construction in the worker so owner/category/provider/version always match the registered ActionType","Assert the owner constant before every poll call in worker startup self-checks"],"tags":["codepipeline","pollforjobs","validation","actiontype"],"backgroundTag":null,"analyzedSha":"62ff490619e7bd3554597c28c704081b4c15add5","analyzedAt":"2026-08-14T14:25:23.764Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}