{"record":{"id":"085ea5f04fa5f90c","repo":"arsduo/koala","slug":"batch-operations-require-an-access-token-none-pro","errorCode":null,"errorMessage":"Batch operations require an access token, none provided.","messagePattern":"Batch operations require an access token, none provided\\.","errorType":"exception","errorClass":"Koala::Facebook::AuthenticationError","httpStatus":null,"severity":"error","filePath":"lib/koala/api/batch_operation.rb","lineNumber":29,"sourceCode":"        @identifier = 0\n\n        def self.next_identifier\n          @identifier += 1\n        end\n\n        def initialize(options = {})\n          @identifier = self.class.next_identifier\n          @args = (options[:args] || {}).dup # because we modify it below\n          @access_token = options[:access_token]\n          @http_options = (options[:http_options] || {}).dup # dup because we modify it below\n          @batch_args = @http_options.delete(:batch_args) || {}\n          @url = options[:url]\n          @method = options[:method].to_sym\n          @post_processing = options[:post_processing]\n\n          process_binary_args\n\n          raise AuthenticationError.new(nil, nil, \"Batch operations require an access token, none provided.\") unless @access_token\n        end\n\n        def to_batch_params(main_access_token, app_secret)\n          # set up the arguments\n          if @access_token != main_access_token\n            @args[:access_token] = @access_token\n            if app_secret\n              @args[:appsecret_proof] = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new(\"sha256\"), app_secret, @access_token)\n            end\n          end\n          args_string = Koala.http_service.encode_params(@args)\n\n          response = {\n            :method => @method.to_s,\n            :relative_url => @url,\n          }\n\n          # handle batch-level arguments, such as name, depends_on, and attached_files","sourceCodeStart":11,"sourceCodeEnd":47,"githubUrl":"https://github.com/arsduo/koala/blob/47d052063ef8b5644fb59e279da0b52687999f55/lib/koala/api/batch_operation.rb#L11-L47","documentation":"Koala::Facebook::BatchOperation raises Koala::Facebook::AuthenticationError in its constructor when the operation carries no access token (lib/koala/api/batch_operation.rb:29). Facebook's batch endpoint executes every bundled operation on behalf of an authenticated user or app, so Koala refuses to build a tokenless batch operation instead of sending a request guaranteed to fail. Like all pre-call guards, the error is created with nil http_status (see the comment in lib/koala/errors.rb:13-14) — no request ever reached Facebook.","triggerScenarios":"Calling api.batch { |batch_api| ... } on a Koala::Facebook::API instance constructed without an access token (e.g. Koala::Facebook::API.new with no argument), or building Koala::Facebook::BatchOperation manually with options[:access_token] nil or absent. The raise fires inside initialize, while the operations are being collected, before the batch HTTP request is assembled.","commonSituations":"Legacy apps that read public data with a tokenless API and later refactor those reads into a batch; the OAuth code-for-token exchange failing silently so nil is passed to API.new; batch code paths that only run in production where ENV['FACEBOOK_ACCESS_TOKEN'] is unset; test suites that stub single calls but never exercise api.batch.","solutions":["Construct the API with a token before batching: Koala::Facebook::API.new(access_token) — api.batch operations inherit it","If the token comes from OAuth, complete and verify the exchange (@oauth.get_access_token(code)) and fail loudly if it returns nil","Check that the token env var / credentials are actually loaded in the environment that runs the batch job","Wrap batch calls in rescue Koala::Facebook::AuthenticationError to route the user back through re-authorization"],"exampleFix":"# before\napi = Koala::Facebook::API.new # no access token\nresults = api.batch do |batch_api|\n  batch_api.get_object('me') # raises AuthenticationError while building the batch\nend\n\n# after\napi = Koala::Facebook::API.new(ENV.fetch('FACEBOOK_ACCESS_TOKEN'))\nresults = api.batch do |batch_api|\n  batch_api.get_object('me')\n  batch_api.get_connections('me', 'friends')\nend","handlingStrategy":"validation","validationCode":"def batchable?(api)\n  !api.access_token.to_s.empty?\nend\n\nraise 'API needs an access token for batch requests' unless batchable?(api)\napi.batch { |batch_api| batch_api.get_object('me') }","typeGuard":null,"tryCatchPattern":"begin\n  api.batch { |batch_api| batch_api.get_object('me') }\nrescue Koala::Facebook::AuthenticationError => e\n  # e.http_status is nil: caught client-side, no request was sent\n  redirect_to oauth_authorization_path\nend","preventionTips":["Instantiate Koala::Facebook::API with the access token at creation so api.batch inherits it","Fail fast at boot for batch jobs: ENV.fetch('FACEBOOK_ACCESS_TOKEN'), never ENV[...] with silent nil","Stub the token in tests that exercise api.batch — a bare API.new raises as soon as a BatchOperation is built","Treat a nil token from OAuth exchange as an error to handle, not a tokenless mode to run in"],"tags":["authentication","access-token","batch-request","facebook-graph-api"],"backgroundTag":"missing-access-token","analyzedSha":"47d052063ef8b5644fb59e279da0b52687999f55","analyzedAt":"2026-08-23T10:19:03.891Z","schemaVersion":2},"datasetVersion":"2026-08-23T13:39:53.451Z"}