floci-io/floci · error · IllegalStateException
${description} file not found or not readable: ${path}
Error message
${description} file not found or not readable: ${path} What it means
Thrown by AcknowledgeJob when the nonce is valid but the job's stored status is not 'Created'. Once a job is acknowledged its status moves to 'InProgress', so a second AcknowledgeJob for the same job is rejected with InvalidJobStateException. This mirrors AWS, where acknowledgment is a one-time transition out of the Created state.
Source
Thrown at src/main/java/io/github/hectorvent/floci/config/TlsConfigSource.java:211
"localhost",
allSans,
KeyAlgorithm.RSA_2048);
Files.writeString(certFile, generated.certificatePem());
Files.writeString(keyFile, generated.privateKeyPem());
LOG.infov("TLS: generated self-signed certificate: {0}", certFile);
// Persist metadata for change detection on restart
persistMetadata(tlsDir, allSans);
} catch (IOException e) {
throw new IllegalStateException("Failed to write self-signed TLS certificate", e);
}
}
private static void validateFileExists(String path, String description) {
if (!Files.isReadable(Path.of(path))) {
throw new IllegalStateException(
description + " file not found or not readable: " + path);
}
}
/**
* Returns {@code true} if the certificate at {@code certFile} is genuinely self-signed
* (issuer == subject) and therefore usable as a trust anchor. Legacy Floci certs carried a
* cosmetic Amazon issuer DN and return {@code false} here, triggering regeneration on upgrade.
*/
private boolean isSelfSigned(Path certFile) {
try {
X509Certificate cert = new CertificateGenerator().parseCertificate(Files.readString(certFile));
return cert.getIssuerX500Principal().equals(cert.getSubjectX500Principal());
} catch (Exception e) {
LOG.warnv("TLS: could not inspect existing certificate ({0}); regenerating", e.getMessage());
return false;
}
}View on GitHub (pinned to 62ff490619)
Solutions
- Treat InvalidJobStateException with 'already been acknowledged' as success in the worker's retry path (idempotency by design)
- Persist the acknowledged jobId locally before retrying so the worker skips re-acknowledgment
- Ensure only one worker instance consumes each polled job
Example fix
// before
client.acknowledgeJob(r -> r.jobId(jobId).nonce(nonce));
// after
try {
client.acknowledgeJob(r -> r.jobId(jobId).nonce(nonce));
} catch (InvalidJobStateException alreadyAcked) {
// first attempt went through; safe to continue processing
} Defensive patterns
Strategy: try-catch
Try / catch
try {
client.acknowledgeJob(r -> r.jobId(jobId).nonce(nonce));
} catch (InvalidJobStateException e) {
if (e.getMessage().contains("already been acknowledged")) {
logger.info("job {} acknowledged by earlier attempt", jobId); // treat as success
} else throw e;
} Prevention
- Record acknowledged jobIds durably before processing so retries skip AcknowledgeJob
- Run one worker per job partition to prevent double acknowledgment
When it happens
Trigger: Calling AcknowledgeJob twice for the same jobId; a worker retry after a network timeout where the first acknowledge actually succeeded; two worker instances picking up the same job (nonce shared) and both acknowledging.
Common situations: At-least-once retry logic in the worker that does not remember prior acknowledgments; duplicated messages in the worker's internal queue; SDK client retries enabled at the HTTP layer causing invisible double submit.
Related errors
- BadRequestException
- Failed to write self-signed TLS certificate
- PipelineNameInUseException
- ActionTypeAlreadyExistsException
- TLS enabled but no certificate provided and self-signed gene
AI-assisted analysis of floci-io/floci@62ff490619 (2026-08-14).
Data as JSON: /api/errors/2746cb29c27c4aab.
Report an issue: GitHub.