HKUDS/Vibe-Trading · critical · ShoonyaConfigError

Shoonya login failed: {error_msg}

Error message

Shoonya login failed: {error_msg}

What it means

Raised by the Shoonya connector's _login helper when the NorenApi login call returns None or a payload whose 'stat' field is not 'Ok'. The upstream error message ('emsg') is embedded when present. It is wrapped as ShoonyaConfigError, meaning the connector treats failed credentials/connectivity at login as a configuration problem.

Source

Thrown at agent/src/trading/connectors/shoonya/sdk.py:590

                websocket="wss://api.shoonya.com/NorenWSTP/",
            )

    api = ShoonyaApi()

    totp = pyotp.TOTP(cfg.totp_secret).now()

    ret = api.login(
        userid=cfg.user_id,
        password=cfg.password,
        twoFA=totp,
        vendor_code=cfg.vendor_code,
        api_secret=cfg.api_secret,
        imei="vibe-trading",
    )

    if ret is None or ret.get("stat") != "Ok":
        error_msg = ret.get("emsg", "Login failed") if ret else "Login returned None"
        raise ShoonyaConfigError(f"Shoonya login failed: {error_msg}")

    _api_cache[cfg.user_id] = api
    return api


def _missing_fields(cfg: ShoonyaConfig) -> list[str]:
    missing = []
    for field in ("user_id", "password", "vendor_code", "api_secret", "totp_secret"):
        if not getattr(cfg, field):
            missing.append(field)
    return missing


def _public_config(cfg: ShoonyaConfig) -> dict[str, Any]:
    data = asdict(cfg)
    for secret in ("password", "api_secret", "totp_secret"):
        if data.get(secret):
            data[secret] = "***redacted***"

View on GitHub (pinned to 80ffdda44c)

Solutions

  1. Verify cfg.user_id, cfg.password, cfg.vendor_token, cfg.api_secret against the Shoonya/Noren developer portal and regenerate the vendor token if stale
  2. Confirm the TOTP/2FA factor value is current and the imei string matches what is registered
  3. Check the configured Norden base URL environment (UAT vs production) matches the credentials
  4. If ret is None, test raw connectivity (curl the Shoonya endpoint) and inspect network/proxy settings
  5. Catch ShoonyaConfigError at the call site and surface the embedded emsg for the broker-side reason

Example fix

# before
cfg = ShoonyaConfig(user_id='u', password='wrong', ...)
api = _login(cfg)  # raises 'Shoonya login failed: ...'

# after
cfg = ShoonyaConfig(user_id='u', password=os.environ['SHOONYA_PASSWORD'],
                    vendor_token=os.environ['SHOONYA_VENDOR_TOKEN'],
                    api_secret=os.environ['SHOONYA_API_SECRET'])
Defensive patterns

Strategy: try-catch

Validate before calling

from agent.src.trading.connectors.shoonya.sdk import ShoonyaConfigError

def can_login(cfg) -> bool:
    missing = _missing_fields(cfg)
    if missing:
        return False
    try:
        _login(cfg)
        return True
    except ShoonyaConfigError:
        return False

Type guard

def is_shoonya_config_error(exc: BaseException) -> bool:
    return isinstance(exc, ShoonyaConfigError) and exc.args[0].startswith('Shoonya login failed')

Try / catch

try:
    snapshot = get_account_snapshot(cfg)
except ShoonyaConfigError as exc:
    if 'login failed' in str(exc):
        logger.error('Shoonya auth rejected: %s', exc)
        # re-read credentials / alert operator; do not retry in a tight loop
    raise

Prevention

When it happens

Trigger: Any call to get_account_snapshot, get_positions, get_open_orders, get_quote, or get_historical_bars on a cold (or invalidated) API cache triggers _login; if userid/password/vendor_token/api_secret/imei are wrong, TOTP is stale, or the Noren endpoint is unreachable, ret is None or stat != 'Ok'.

Common situations: Expired or changed Shoonya password, wrong vendor code/token/secret pair, missing TOTP factor, base URL pointing at the wrong environment (uat vs prod), or network/firewall blocking the broker's REST endpoint.

Related errors


AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28). Data as JSON: /api/errors/2a465dd54115c4c3. Report an issue: GitHub.