{"record":{"id":"99f4d72f66c15c21","repo":"we-promise/sure","slug":"invalid-environment-environment","errorCode":null,"errorMessage":"Invalid environment: #{environment}","messagePattern":"Invalid environment: #(.+?)","errorType":"validation","errorClass":"Provider::Trading212::ConfigurationError","httpStatus":null,"severity":"error","filePath":"app/models/provider/trading212.rb","lineNumber":42,"sourceCode":"\n  RETRYABLE_ERRORS = [\n    SocketError,\n    Net::OpenTimeout,\n    Net::ReadTimeout,\n    Errno::ECONNRESET,\n    Errno::ECONNREFUSED,\n    Errno::ETIMEDOUT,\n    EOFError\n  ].freeze\n\n  default_options.merge!({ timeout: 60 }.merge(httparty_ssl_options))\n\n  attr_reader :api_key, :api_secret, :environment\n\n  def initialize(api_key:, api_secret:, environment: \"live\")\n    raise ConfigurationError, \"api_key is required\" if api_key.blank?\n    raise ConfigurationError, \"api_secret is required\" if api_secret.blank?\n    raise ConfigurationError, \"Invalid environment: #{environment}\" unless %w[live demo].include?(environment.to_s)\n\n    @api_key = api_key.to_s.strip\n    @api_secret = api_secret.to_s.strip\n    @environment = environment.to_s\n  end\n\n  def fetch_account_summary\n    get(\"/equity/account/summary\")\n  end\n\n  def fetch_positions\n    get(\"/equity/positions\")\n  end\n\n  def fetch_instruments\n    get(\"/equity/metadata/instruments\")\n  end\n","sourceCodeStart":24,"sourceCodeEnd":60,"githubUrl":"https://github.com/we-promise/sure/blob/e69894adb92547273377398c15f45c979cd9416a/app/models/provider/trading212.rb#L24-L60","documentation":"Provider::Trading212::ConfigurationError raised when the environment argument is not exactly \"live\" or \"demo\" (case-sensitive after to_s). The environment selects the base URI: live.trading212.com vs demo.trading212.com, so an unknown value has no endpoint to target.","triggerScenarios":"Passing environment: \"production\", \"Live\" (capital L), \"sandbox\", \"test\", or a symbol like :live is fine (to_s) but :prod fails; passing nil (default \"live\" only applies when the arg is omitted, nil explicitly fails the include? check after to_s → \"\").","commonSituations":"UI dropdown saving a label like \"Live account\" instead of the value \"live\"; a config file renamed environments to production/staging; passing an unvalidated user-supplied string straight through.","solutions":["Pass exactly \"live\" or \"demo\": Provider::Trading212.new(api_key:, api_secret:, environment: \"demo\")","Whitelist and normalize in the caller before constructing: env = %w[live demo].include?(env.to_s.downcase) ? env.to_s.downcase : nil, and surface a validation message for anything else","If the value comes from a form, store the machine value (\"live\"/\"demo\") not the display label","Omit the argument entirely when you want the default \"live\" environment"],"exampleFix":"// before\nProvider::Trading212.new(api_key:, api_secret:, environment: params[:environment]) # \"Live\" -> raises\n\n// after\nenv = params[:environment].to_s.downcase\nenv = \"live\" unless %w[live demo].include?(env)\nProvider::Trading212.new(api_key:, api_secret:, environment: env)","handlingStrategy":"validation","validationCode":"environment = params[:environment].to_s.downcase\nunless %w[live demo].member?(environment)\n  raise ArgumentError, \"environment must be 'live' or 'demo', got #{environment.inspect}\"\nend","typeGuard":null,"tryCatchPattern":"begin\n  Provider::Trading212.new(api_key:, api_secret:, environment: env)\nrescue Provider::Trading212::ConfigurationError => e\n  # treat as programmer/form error — do not retry, fix the input\nend","preventionTips":["Use a form select with machine values live/demo, never free text","Normalize case and whitespace before passing","Add a unit test asserting both accepted values and rejection of 'production'/'staging'"],"tags":["ruby","trading212","configuration","invalid-enum","environment"],"backgroundTag":"invalid-configuration-value","analyzedSha":"e69894adb92547273377398c15f45c979cd9416a","analyzedAt":"2026-08-21T18:22:41.165Z","schemaVersion":2},"datasetVersion":"2026-08-21T23:17:16.201Z"}