puma/puma · error · ArgumentError
No such truststore file '#{truststore}'
Error message
No such truststore file '#{truststore}' What it means
JRuby-only: MiniSSL::Context#truststore= (lib/puma/minissl.rb:248) validates the truststore path unless the value is exactly the symbol :default (which opts out and uses the JVM's default trust anchors). Any other value must point to an existing file or ArgumentError is raised.
Source
Thrown at lib/puma/minissl.rb:248
attr_reader :keystore
attr_reader :keystore_type
attr_accessor :keystore_pass
attr_reader :truststore
attr_reader :truststore_type
attr_accessor :truststore_pass
attr_reader :cipher_suites
attr_reader :protocols
def keystore=(keystore)
check_file keystore, 'Keystore'
@keystore = keystore
end
def truststore=(truststore)
# NOTE: historically truststore was assumed the same as keystore, this is kept for backwards
# compatibility, to rely on JVM's trust defaults we allow setting `truststore = :default`
unless truststore.eql?(:default)
raise ArgumentError, "No such truststore file '#{truststore}'" unless File.exist?(truststore)
end
@truststore = truststore
end
def keystore_type=(type)
raise ArgumentError, "Invalid keystore type: #{type.inspect}" unless ['pkcs12', 'jks', nil].include?(type)
@keystore_type = type
end
def truststore_type=(type)
raise ArgumentError, "Invalid truststore type: #{type.inspect}" unless ['pkcs12', 'jks', nil].include?(type)
@truststore_type = type
end
def cipher_suites=(list)
list = list.split(',').map(&:strip) if list.is_a?(String)
@cipher_suites = list
endView on GitHub (pinned to b8341dc946)
Solutions
- Create/copy the truststore (e.g. keytool -importcert) and point to its absolute path
- To rely on JVM defaults, pass `ssl_truststore: 'default'` through ssl_bind
- If configuring Context directly in Java/JRuby code, use the symbol :default, not the string
Example fix
# before
ssl_bind '0.0.0.0', '9292', {
keystore: 'keystore.jks',
'truststore' => '/etc/puma/truststore.jks' # file not present
}
# after - use JVM default trust anchors
ssl_bind '0.0.0.0', '9292', {
keystore: 'keystore.jks',
'truststore' => 'default'
} Defensive patterns
Strategy: validation
Validate before calling
ts = ENV['SSL_TRUSTSTORE']
ssl_bind host, port, {
keystore: keystore,
truststore: (ts == 'default' || File.exist?(ts) ? ts : abort("missing truststore #{ts}"))
} Prevention
- Remember `truststore 'default'` means JVM trust anchors; only via ssl_bind is the string converted to the symbol
- Provision truststores with keytool before deploy, alongside the keystore
- Use absolute paths for JVM-related files
When it happens
Trigger: `ssl_bind` with a truststore option whose path does not exist on disk. Note the standard ContextBuilder converts the string 'default' to :default (lib/puma/minissl/context_builder.rb:27), so :default handling only applies through ssl_bind - assigning ctx.truststore = 'default' (String) directly checks for a literal file named 'default'.
Common situations: Porting an MRI puma config to JRuby where the truststore was never provisioned; wrong path after switching from system JAVA_HOME cacerts to a custom truststore; typos in the path.
Related errors
- Invalid keystore type: #{type.inspect}
- Invalid truststore type: #{type.inspect}
- #{desc} file '#{file}' does not exist
- Invalid value of no_tlsv1=
- Invalid value of no_tlsv1_1=
AI-assisted analysis of puma/puma@b8341dc946 (2026-08-21).
Data as JSON: /api/errors/f560419af422d235.
Report an issue: GitHub.