org.llm4s.core.safety

Members list

Type members

Classlikes

@Stable

Default mapping.

Default mapping.

A cancellation - mapped while the current thread is interrupted, or caused by an InterruptedException or ClosedByInterruptException (see CancelledError.isCancellation) - becomes a CancelledError. Mapping classifies only and never sets the interrupt flag: it may run on a thread other than the interrupted one, such as a Future callback's pool thread.

An exception whose message names HTTP status 401 becomes an AuthenticationError (code 401, carrying the redacted message), and one naming 429 a RateLimitError; 401 wins when a message names both. A message names a status only in an HTTP context, at a word boundary: after HTTP, status, status code, http status, error code or response code, optionally quoted as a JSON key (HTTP 401, Status Code: 429, "status": 401, http_status=429), before its reason phrase (401 Unauthorized, 429 Too Many Requests), or leading the message as openai-java and anthropic-java write it (401: <body>, also behind up to eight wrapping exceptions' ClassName:). A message that merely contains the digits - an index, an id, a port or a count - is an UnknownError carrying the exception as its cause, as is anything else not matched above.

Known false positive: that last, SDK shape carries no other HTTP marker, so any message that starts with 401: or 429: (optionally behind SomeException: prefixes) is classified, even when the number means something else, such as a line number in 429: unexpected token.

Only the first 4 KiB and the last 1 KiB of a message are scanned (see ScanHead), and every pattern runs in linear time, so mapping an exception that carries a large response body is cheap.

The message of every error built here is redacted and capped (Redaction.safeBody), since an exception's message often echoes a provider's response body and with it a request header or a key. The cause is not: an UnknownError keeps the original exception, whose own getMessage and stack trace are unredacted. A logger or handler that prints the cause (logger.error(msg, err.cause), printStackTrace) writes that text in the clear.

Attributes

Supertypes
trait ErrorMapper
class Object
trait Matchable
class Any
Self type
@Stable
trait ErrorMapper

Maps arbitrary Throwables into domain-specific LLMError values.

Maps arbitrary Throwables into domain-specific LLMError values.

Attributes

Supertypes
class Object
trait Matchable
class Any
Known subtypes
@Stable

Network security utilities for SSRF protection.

Network security utilities for SSRF protection.

Provides IP address validation to prevent Server-Side Request Forgery (SSRF) attacks by blocking requests to internal networks, cloud metadata endpoints, and other potentially sensitive destinations.

== Protected IP Ranges == Checked against the IANA IPv4 and IPv6 Special-Purpose Address Registries: every entry that is not globally reachable is blocked.

  • Private networks: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 (RFC 1918); IPv6 unique-local fc00::/7 (RFC 4193) and the deprecated site-local fec0::/10
  • Loopback: 127.0.0.0/8, ::1
  • Unspecified / "this network": 0.0.0.0/8, ::
  • Link-local: 169.254.0.0/16, fe80::/10
  • Cloud metadata: 169.254.169.254 (AWS, GCP, Azure)
  • Multicast: 224.0.0.0/4, ff00::/8
  • Reserved 240.0.0.0/4, including the limited broadcast address 255.255.255.255
  • IETF protocol assignments 192.0.0.0/24 and the deprecated 6to4 relay anycast 192.88.99.0/24
  • Carrier-grade NAT 100.64.0.0/10, benchmarking 198.18.0.0/15 and 2001:2::/48
  • Documentation/test ranges: 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 2001:db8::/32, 3fff::/20
  • Every IPv6 address outside global unicast 2000::/3 (RFC 4291 2.4), which IANA has never allocated for routing: among others the IPv4-compatible ::/96, the SIIT IPv4-translated ::ffff:0:0:0/96, discard-only 100::/64, the dummy prefix 100:0:0:1::/64, local-use NAT64 64:ff9b:1::/48 and SRv6 5f00::/16
  • The IETF protocol assignments block 2001::/23 (Teredo 2001::/32, benchmarking, the deprecated ORCHID and the unassigned rest), except its globally reachable entries: 2001:1::1, 2001:1::2 and 2001:1::3, AMT 2001:3::/32, AS112 2001:4:112::/48, ORCHIDv2 2001:20::/28 and drone remote ID 2001:30::/28
  • An IPv6 address that embeds an IPv4 address - IPv4-mapped ::ffff:0:0/96, NAT64 64:ff9b::/96 and 6to4 2002::/16 - is blocked when the embedded IPv4 address is

The globally reachable entries of the IPv4 registry (192.31.196.0/24, 192.52.193.0/24, 192.175.48.0/24) are allowed.

== Name resolution == validateUrl and validateHostname resolve the host with InetAddress.getAllByName, which cannot be interrupted: a caller that runs them under a deadline (as the HTTP tool does) can stop waiting, but the thread doing the lookup stays blocked until the system resolver answers or gives up, by its own timeout. The address is resolved again when the connection is made, so a host whose answer changes in between (DNS rebinding) is not covered.

Attributes

Example
import org.llm4s.core.safety.NetworkSecurity
// Validate a URL before fetching
NetworkSecurity.validateUrl("https://example.com/api") // Right(())
NetworkSecurity.validateUrl("http://169.254.169.254/") // Left(NetworkError)
NetworkSecurity.validateUrl("http://192.168.1.1/admin") // Left(NetworkError)
Supertypes
class Object
trait Matchable
class Any
Self type
@Stable
object Safety

Pure helpers for safe, typed error handling. All helpers return Either-based results.

Pure helpers for safe, typed error handling. All helpers return Either-based results.

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
Safety.type
@Stable
object UsingOps

Resource management helpers for automatic cleanup This file legitimately needs try-finally for low-level resource management

Resource management helpers for automatic cleanup This file legitimately needs try-finally for low-level resource management

Attributes

Supertypes
class Object
trait Matchable
class Any
Self type
UsingOps.type