spring-projects/spring-ai · error · RuntimeException
IOException (wrapped RuntimeException)
Error message
IOException (wrapped RuntimeException)
What it means
ResourceUtils.getText loads a Spring Resource from a URI and reads it fully as UTF-8 text; any IOException (missing resource, unreadable file, bad URL) is rethrown as an unchecked RuntimeException wrapping the cause. There is no dedicated exception type, so callers must unwrap the cause to learn what failed.
Source
Thrown at spring-ai-commons/src/main/java/org/springframework/ai/util/ResourceUtils.java:49
/**
* Retrieves the content of a resource as a UTF-8 encoded string.
*
* This method uses Spring's DefaultResourceLoader to load the resource from the given
* URI and then reads its content as a string using UTF-8 encoding. If an IOException
* occurs during reading, it is wrapped in a RuntimeException.
* @param uri The URI of the resource to be read. This can be any URI supported by
* Spring's ResourceLoader, such as "classpath:", "file:", or "http:".
* @return The content of the resource as a string.
* @throws RuntimeException If an error occurs while reading the resource. This
* exception wraps the original IOException.
*/
public static String getText(String uri) {
var resource = new DefaultResourceLoader().getResource(uri);
try {
return resource.getContentAsString(StandardCharsets.UTF_8);
}
catch (IOException e) {
throw new RuntimeException(e);
}
}
}
View on GitHub (pinned to 98a7beda4f)
Solutions
- Unwrap e.getCause() (IOException) to see whether it's FileNotFoundException vs connection failure
- Verify the resource exists: new DefaultResourceLoader().getResource(uri).exists() before getText
- For classpath resources confirm the file is under src/main/resources and packaged in the jar
- Use file:/ or classpath:/ prefixes explicitly instead of relying on relative paths
Example fix
// before
String prompt = ResourceUtils.getText("classpath:prompts/sys.txt");
// after
Resource r = new DefaultResourceLoader().getResource("classpath:prompts/sys.txt");
Assert.isTrue(r.exists(), "Missing prompt resource: prompts/sys.txt");
String prompt = ResourceUtils.getText("classpath:prompts/sys.txt"); Defensive patterns
Strategy: validation
Validate before calling
Resource r = new DefaultResourceLoader().getResource(uri);
if (!r.exists()) throw new IllegalStateException("Resource not found: " + uri); Try / catch
try {
String text = ResourceUtils.getText(uri);
} catch (RuntimeException e) {
throw new IllegalStateException("Cannot load resource " + uri + ": " + e.getCause().getMessage(), e.getCause());
} Prevention
- Check resource.exists() before reading
- Use explicit classpath:/file:/ prefixes
- Ensure prompt files are under src/main/resources and packaged
- Cache resources at startup to fail fast
When it happens
Trigger: Calling ResourceUtils.getText("classpath:prompt.txt") with a resource that does not exist, a wrong URL, an unreadable file path, or a network resource that is unavailable.
Common situations: Typo'd classpath resource name; file left out of the packaged jar (not in src/main/resources); loading prompts from a remote URL behind auth; running from a different working directory with relative file paths.
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to read resource
- Failed to read resource:
- Failed to cache the resource:
- java.io.IOException
- java.io.IOException
AI-assisted analysis of spring-projects/spring-ai@98a7beda4f (2026-09-11).
Data as JSON: /api/errors/96ec5ef4d63823b9.
Report an issue: GitHub.