{"record":{"id":"6b51bb0574193c1e","repo":"we-promise/sure","slug":"unsupported-binance-ticker-symbol","errorCode":null,"errorMessage":"Unsupported Binance ticker: #{symbol}","messagePattern":"Unsupported Binance ticker: #(.+?)","errorType":"exception","errorClass":"Provider::BinancePublic::Error","httpStatus":null,"severity":"error","filePath":"app/models/provider/binance_public.rb","lineNumber":156,"sourceCode":"          name: base,\n          # Brandfetch /crypto/{base} URL — unknown coins (rare) will 400 and\n          # render as a broken img in the dropdown; same tradeoff as stocks\n          # with obscure tickers. `::Security` reaches the AR model —\n          # unqualified `Security` here resolves to the Data value-object\n          # from SecurityConcept.\n          logo_url: ::Security.brandfetch_crypto_url(base),\n          exchange_operating_mic: BINANCE_MIC,\n          country_code: nil,\n          currency: display_currency\n        )\n      end\n    end\n  end\n\n  def fetch_security_info(symbol:, exchange_operating_mic:)\n    with_provider_response do\n      parsed = parse_ticker(symbol)\n      raise Error, \"Unsupported Binance ticker: #{symbol}\" if parsed.nil?\n\n      # logo_url is intentionally nil — crypto logos are set at save time by\n      # Security#generate_logo_url_from_brandfetch via the /crypto/{base}\n      # route, not returned from this provider.\n      links = parsed[:binance_pair] ? \"https://www.binance.com/en/trade/#{parsed[:binance_pair]}\" : nil\n\n      SecurityInfo.new(\n        symbol: symbol,\n        name: parsed[:base],\n        links: links,\n        logo_url: nil,\n        description: nil,\n        kind: \"crypto\",\n        exchange_operating_mic: exchange_operating_mic\n      )\n    end\n  end\n","sourceCodeStart":138,"sourceCodeEnd":174,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/binance_public.rb#L138-L174","documentation":"Raised by Provider::BinancePublic#fetch_security_info when parse_ticker(symbol) returns nil — the symbol does not match the ticker grammar this provider supports (crypto base/quote pairs recognized around parse_ticker at binance_public.rb:324). It is raised as Provider::BinancePublic::Error, aborting the SecurityInfo lookup before any HTTP call.","triggerScenarios":"Passing a non-crypto symbol (\"AAPL\") or a malformed crypto symbol to fetch_security_info; a quote asset the parser does not map to a Binance pair; a symbol with unexpected separators/casing; calling the securities provider with exchange_operating_mic for a different exchange but a Binance-only code path.","commonSituations":"Auto-sync iterating a mixed portfolio (stocks + crypto) and routing every symbol to BinancePublic; user-typed symbols that skip normalization; symbol data imported from another provider (e.g. \"BTC-USD\" style vs the expected format); legacy Security rows with odd symbols.","solutions":["Check what parse_ticker expects (binance_public.rb:324) and conform the symbol to that format before calling.","Gate calls: only route crypto symbols to BinancePublic (e.g. via exchange MIC == BINANCE_MIC or a crypto asset type), never equities.","Rescue Provider::BinancePublic::Error in lookups so one unsupported ticker does not break a bulk refresh.","If the symbol should be supported, verify the quote currency is one the parser recognizes and fix/extend the mapping."],"exampleFix":"# before\ninfo = provider.fetch_security_info(symbol: \"AAPL\", exchange_operating_mic: \"BINANCE\") # raises\n\n# after\ncrypto_symbol = symbol if mic == \"BINANCE\"\ninfo = provider.fetch_security_info(symbol: crypto_symbol, exchange_operating_mic: mic) if crypto_symbol.present?","handlingStrategy":"validation","validationCode":"CRYPTO_PAIR = /\\A[A-Z0-9]{2,10}-(USDT|USDC|FDUSD|USD|BTC|ETH)\\z/\nreturn unless mic == \"BINANCE\" && symbol.match?(CRYPTO_PAIR)","typeGuard":"def binance_ticker?(symbol, mic)\n  mic == \"BINANCE\" && symbol.match?(%r{\\A[A-Z0-9]{2,10}-(USDT|USDC|FDUSD|USD)\\z}).present?\nend","tryCatchPattern":"begin\n  info = provider.fetch_security_info(symbol: sym, exchange_operating_mic: mic)\nrescue Provider::BinancePublic::Error => e\n  Rails.logger.warn(\"SecurityInfo skipped for #{sym}: #{e.message}\")\n  nil\nend","preventionTips":["Route only crypto securities with the Binance MIC to BinancePublic; equities belong to other providers.","Conform symbols to the format parse_ticker accepts (see binance_public.rb:324) before calling.","Validate symbol shape at import time (regex on symbol + MIC) so bad rows never reach the provider.","Rescue per-symbol in bulk lookups and quarantine offenders."],"tags":["binance","symbol-parsing","securities","crypto","validation"],"backgroundTag":"unsupported-symbol","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}