iflytek/astron-agent · error · IOException
Skill resource URL is not allowed
Error message
Skill resource URL is not allowed
What it means
downloadText first validates the skill resource URL (validateResourceUrl, origin/allow-list enforcement) and then builds the OkHttp request. If Request.Builder().url(url) throws IllegalArgumentException (malformed URL), it is converted to an IOException "Skill resource URL is not allowed". The message deliberately does not distinguish malformed URL from policy-rejected so callers learn nothing about the validation internals.
Solutions
- Check the URL is absolute, well-formed, and uses the allowed scheme/host required by validateResourceUrl.
- Point the skill resource at the approved same-origin host (e.g. the skill repository service) instead of a foreign origin.
- Validate/normalize URLs in the skill manifest at publish time so bad URLs never reach runtime.
- If a legitimate host is blocked, add it to the configured allow-list — do not bypass the validation.
Example fix
// before
String text = service.downloadText("skills.example.com/file.txt"); // no scheme -> IllegalArgumentException -> IOException
// after
URL u = new URI("https://skills.internal.example.com/file.txt").toURL(); // absolute, allow-listed origin
if (u.getHost().endsWith(".internal.example.com")) {
String text = service.downloadText(u.toString());
} Defensive patterns
Strategy: validation
Validate before calling
boolean isAllowedResourceUrl(String url) {
try {
URI u = new URI(url);
String scheme = u.getScheme();
String host = u.getHost();
return ("https".equals(scheme) || "http".equals(scheme))
&& host != null && host.endsWith(".internal.example.com");
} catch (URISyntaxException e) {
return false;
}
} Type guard
boolean isAbsoluteHttpUrl(String url) {
try {
URI u = new URI(url);
return u.isAbsolute() && u.getHost() != null;
} catch (URISyntaxException e) {
return false;
}
} Try / catch
try {
String content = service.downloadText(url, limit);
} catch (IOException e) {
if ("Skill resource URL is not allowed".equals(e.getMessage())) {
// reject the skill resource: malformed or non-allow-listed origin
}
} Prevention
- Validate skill resource URLs at skill publish time, not only at runtime.
- Keep skill manifests referencing only allow-listed hosts.
- Normalize URLs (add scheme, resolve relative paths) before calling downloadText.
When it happens
Trigger: Calling downloadText (via skill resource read) with a URL that fails validateResourceUrl (foreign origin, non-allow-listed host, disallowed scheme) or with a syntactically invalid URL string that OkHttp cannot parse.
Common situations: A skill's resource reference points to an external host not on the allow-list (SSRF protection); a skill manifest contains a relative or malformed URL; the URL was attacker-controlled and got rejected by design; scheme is ftp:// or file:// instead of http(s).
Understand the failure class
Background: "Invalid URL" / "URL cannot be empty": fix the malformed or missing URL behind request-construction failures — this error's family across 50 libraries.
Related errors
- TOOLBOX_URL_HTTP_HTTPS_ONLY
- exceeds size limit
- MODEL_URL_CHECK_FAILED
- MODEL_URL_CHECK_FAILED
- MODEL_URL_ILLEGAL_FAILED
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/ad799bf458fc0028.
Report an issue: GitHub.
Appendix: source
Thrown at console/backend/hub/src/main/java/com/iflytek/astron/console/hub/service/chat/springai/SkillRuntimeToolService.java:114
}
ResponseBody respBody = response.body();
return respBody == null
? ""
: decodeText(
readBounded(respBody, maxSandboxResponseBytes, "Sandbox response"),
respBody);
}
}
/** Download a text resource (SKILL.md or a referenced file) from a presigned URL. */
public String downloadText(String url) throws IOException {
validateLimit(maxResourceBytes, "Skill resource");
validateResourceUrl(url);
Request request;
try {
request = new Request.Builder().url(url).get().build();
} catch (IllegalArgumentException exception) {
throw new IOException("Skill resource URL is not allowed");
}
OkHttpClient client = httpClient.newBuilder()
.callTimeout(Duration.ofSeconds(30))
.followRedirects(false)
.followSslRedirects(false)
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("Skill resource download failed: HTTP " + response.code());
}
ResponseBody body = response.body();
if (body == null) {
throw new IOException("Skill resource download returned empty body");
}
return decodeText(readBounded(body, maxResourceBytes, "Skill resource"), body);
}
}
View on GitHub (pinned to 5e758547a8)