HKUDS/Vibe-Trading · critical · TigerConfigError
Tiger private key not found at {key_path}
Error message
Tiger private key not found at {key_path} What it means
_client_config expands cfg.private_key_path and requires the file to exist before calling tigeropen's read_private_key. A missing key file is classified as TigerConfigError rather than an auth failure, because the connector treats key material location as configuration. The path is used exactly as configured (with ~ expansion but no search of default locations).
Source
Thrown at agent/src/trading/connectors/tiger/sdk.py:565
def _require_tigeropen() -> ModuleType:
try:
import tigeropen # type: ignore
except ModuleNotFoundError as exc:
raise TigerDependencyError("tigeropen is not installed; run `pip install tigeropen`.") from exc
return tigeropen
def _client_config(cfg: TigerConfig):
"""Build a ``TigerOpenClientConfig`` from connector settings."""
_require_tigeropen()
from tigeropen.common.util.signature_utils import read_private_key # type: ignore
from tigeropen.tiger_open_config import TigerOpenClientConfig # type: ignore
key_path = Path(cfg.private_key_path).expanduser()
if not key_path.exists():
raise TigerConfigError(f"Tiger private key not found at {key_path}")
client_config = TigerOpenClientConfig()
client_config.private_key = read_private_key(str(key_path))
client_config.tiger_id = cfg.tiger_id
client_config.account = cfg.account
try:
client_config.timeout = cfg.timeout
except Exception: # noqa: BLE001 - older SDKs may not expose timeout
pass
return client_config
def _trade_client(cfg: TigerConfig):
_require_tigeropen()
from tigeropen.trade.trade_client import TradeClient # type: ignore
return TradeClient(_client_config(cfg))
View on GitHub (pinned to 80ffdda44c)
Solutions
- Verify the path: ls -l the exact expanded value of cfg.private_key_path
- Download/regenerate the RSA private key from the Tiger OpenAPI portal and place it at the configured path
- Use an absolute path or '~' (expanduser is applied) rather than '$HOME' or relative paths
- In containers, ensure the key is mounted/secret-injected before the connector starts
Example fix
# before
{"private_key_path": "/home/dev/keys/tiger.pem"} # missing on server
# after
{"private_key_path": "/etc/vibetrading/secrets/tiger_private_key.pem"} Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
def key_present(cfg) -> bool:
return bool(cfg.private_key_path) and Path(cfg.private_key_path).expanduser().is_file() Type guard
def has_valid_key_path(cfg: TigerConfig) -> bool:
p = Path(cfg.private_key_path or '').expanduser()
return p.is_file() and p.stat().st_size > 0 Try / catch
try:
positions = get_positions(cfg)
except TigerConfigError as exc:
if 'private key not found' in str(exc):
logger.error('Missing Tiger key at %s — mount/regenerate it', cfg.private_key_path)
raise Prevention
- Use absolute paths for key material in deployed configs
- Add a preflight check at startup that all configured key files exist and are readable
- Mount secrets into the container before app start and verify in a health check
When it happens
Trigger: Calling any function that builds a Tiger client (_trade_client, _quote_client -> _client_config) when cfg.private_key_path points to a nonexistent path — typo, unexpanded env var, absolute path valid only on another machine, or key file never downloaded from Tiger's developer portal.
Common situations: Config written on a dev machine with a home-relative path that differs in deployment; SSH key generated but saved elsewhere; container lacking the mounted secret; path containing '$HOME' literally instead of '~' or an expanded absolute path.
Related errors
- profile must be 'paper', 'live-readonly' or 'live'
- invalid Tiger config at {path}: {exc}
- Tiger account number is not configured
- {str(e)}
- Feishu QR login requires a JSON agent config; use ~/.vibe-tr
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/224119646edacbf6.
Report an issue: GitHub.