iflytek/astron-agent · error · RuntimeError
Sandbox runtime configuration is unavailable
Error message
Sandbox runtime configuration is unavailable
What it means
_load_runtime_config_url validates SKILL_SANDBOX_RUNTIME_CONFIG_URL with the same strict rules as the artifact upload URL but for the runtime-config path: scheme http/https, hostname present, no userinfo, path exactly '/skill-sandbox/internal-runtime-config', no query/fragment, <= 2048 chars, no control chars, valid port. Violations become RuntimeError('Sandbox runtime configuration is unavailable'), raised when _fetch_e2b_runtime_config runs.
Solutions
- Set SKILL_SANDBOX_RUNTIME_CONFIG_URL to the exact URL ending in /skill-sandbox/internal-runtime-config, e.g. https://sandbox.example.com/skill-sandbox/internal-runtime-config
- Remove query strings, fragments, credentials, or control characters and keep total length <= 2048
- Check docker-compose/helm values so the variable is actually substituted (not left as an empty string) at deploy time
- Confirm the path against the deployed sandbox runtime-config service version
Example fix
// before SKILL_SANDBOX_RUNTIME_CONFIG_URL=https://sandbox.example.com // after SKILL_SANDBOX_RUNTIME_CONFIG_URL=https://sandbox.example.com/skill-sandbox/internal-runtime-config
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlsplit
RUNTIME_CONFIG_PATH = "/skill-sandbox/internal-runtime-config"
def runtime_config_url_ok() -> bool:
url = (os.getenv("SKILL_SANDBOX_RUNTIME_CONFIG_URL") or "").strip()
if not url or len(url) > 2048 or any(c in url for c in "\r\n\t"):
return False
p = urlsplit(url)
try:
p.port
except ValueError:
return False
return (
p.scheme in ("http", "https")
and bool(p.hostname)
and p.username is None
and p.password is None
and p.path == RUNTIME_CONFIG_PATH
and not p.query
and not p.fragment
) Type guard
from urllib.parse import urlsplit
def is_valid_runtime_config_url(url: object) -> bool:
if not isinstance(url, str) or not url:
return False
p = urlsplit(url)
return p.scheme in ("http", "https") and bool(p.hostname) and p.path == "/skill-sandbox/internal-runtime-config" Try / catch
try:
config = await _fetch_e2b_runtime_config()
except RuntimeError as exc:
if "Sandbox runtime configuration" in str(exc):
raise ConfigError(
"SKILL_SANDBOX_RUNTIME_CONFIG_URL missing/malformed; must end in "
"/skill-sandbox/internal-runtime-config"
) from exc
raise Prevention
- Set the full path URL, not the service root, in compose/helm values
- Check rendered templates (`docker compose config`) so unresolved ${VAR} substitutions are caught before deploy
- Run the same URL allowlist validation in a pre-deploy smoke test
- Keep the runtime-config endpoint path in sync with the sandbox service version you deploy
When it happens
Trigger: _fetch_e2b_runtime_config invoked (sandbox script execution path) while SKILL_SANDBOX_RUNTIME_CONFIG_URL is unset/empty, points to the wrong path (not /skill-sandbox/internal-runtime-config), uses a non-http(s) scheme, contains credentials/query/fragment/control characters, exceeds 2048 chars, or has an invalid port — converted at line 216.
Common situations: E2B sandbox configured with a token/URL pair for a different endpoint version; operator set the root URL without the internal-runtime-config path; the runtime-config service was moved behind a gateway that appends a path prefix; empty env var after a broken docker-compose variable substitution (`${VAR}` left blank).
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
- Artifact upload configuration is unavailable
- Artifact upload credential is missing or invalid
- Sandbox initialization failed
- 40028
- Invalid PRIVATE_ENDPOINT_ALLOW_LIST entry
AI-assisted analysis of iflytek/astron-agent@5e758547a8 (2026-09-12).
Data as JSON: /api/errors/4fc82f640a01f1be.
Report an issue: GitHub.
Appendix: source
Thrown at core/agent/service/plugin/skill_sandbox.py:216
runtime_config_url = (os.getenv(RUNTIME_CONFIG_URL_ENV) or "").strip()
try:
parsed = urlsplit(runtime_config_url)
if (
not runtime_config_url
or len(runtime_config_url) > 2048
or any(char in runtime_config_url for char in ("\r", "\n", "\t"))
or parsed.scheme not in {"http", "https"}
or not parsed.hostname
or parsed.username is not None
or parsed.password is not None
or parsed.path != RUNTIME_CONFIG_PATH
or bool(parsed.query)
or bool(parsed.fragment)
):
raise ValueError
parsed.port
except (TypeError, ValueError):
raise RuntimeError(SANDBOX_RUNTIME_CONFIG_ERROR) from None
return runtime_config_url
def _load_runtime_credential_token() -> str:
token = (os.getenv(RUNTIME_CREDENTIAL_TOKEN_ENV) or "").strip()
if not token:
token_file = (os.getenv(RUNTIME_CREDENTIAL_TOKEN_FILE_ENV) or "").strip()
if token_file:
try:
token = Path(token_file).read_text(encoding="utf-8").strip()
except (OSError, UnicodeError):
raise RuntimeError(SANDBOX_RUNTIME_CONFIG_ERROR) from None
if (
len(token) < MIN_RUNTIME_CREDENTIAL_TOKEN_LENGTH
or "\r" in token
or "\n" in token
):
raise RuntimeError(SANDBOX_RUNTIME_CONFIG_ERROR)View on GitHub (pinned to 5e758547a8)