karatelabs/karate

karate.set(callSingle()) + call read() in Background freezes Outline row values

Open

#2,934 opened on Jun 19, 2026

View on GitHub
 (1 comment) (0 reactions) (0 assignees)Java (1,893 forks)batch import
bughelp wanted

Repository metrics

Stars
 (7,600 stars)
PR merge metrics
 (Avg merge 14h 17m) (25 merged PRs in 30d)

Description

Description

When a Scenario Outline Background uses karate.set(karate.callSingle('feature')) followed by call read('feature'), all Outline rows receive row 1's Examples column values. The scope is frozen after row 1 — subsequent rows don't get their own values applied to #() expressions in the request body.

Observation- karate.set(callSingle()) followed by any call read() (with or without HTTP call) in Background seems to be the trigger. Neither alone triggers the issue — it's the combination.

Impact- The scope freeze affects BOTH the #() expressions in request bodies AND the variable references in assertions. Tests may false-pass because both the sent data and the expected values are frozen to row 1's values (Alice == Alice passes for all rows). The reproduction uses __num to reliably detect the freeze.

Steps to Reproduce

  1. Create a feature file using the snippets below.
Feature: karate.set(callSingle()) + call read() in Background freezes Outline row values

  Background:
    * karate.set( karate.callSingle('classpath:v2MigrationBugs/callSingleSetOutlineRows/constants.feature') )

    * def bgResult = call read('classpath:v2MigrationBugs/callSingleSetOutlineRows/bgNoHttpCall.feature')
    * def existingItems = bgResult.items || []

  Scenario Outline: Row <rowNum> - each row must have its own phoneNumber
    * def expectedPhones = ['1111111111', '2222222222', '3333333333', '4444444444']
    * def expectedPhone = expectedPhones[__num]

    # This assertion WILL FAIL on rows 2-4 if scope is frozen:
    # phone will be '1111111111' (row 1's value) but expectedPhone will differ
    * match phone == expectedPhone

    Examples:
    | fName!    | lName!   | phone!       | active! | rowNum! |
    | 'Alice'   | 'Smith'  | '1111111111' | true    | 1       |
    | 'Bob'     | 'Jones'  | '2222222222' | false   | 2       |
    | 'Charlie' | 'Brown'  | '3333333333' | true    | 3       |
    | 'Diana'   | 'Prince' | '4444444444' | false   | 4       |
  1. Create a feature file using the snippets below for constants.feature being called in the above feature from callSingle
@ignore
Feature: Simulated Pre-req (callSingle-cached, returns object for karate.set)

  Scenario:
    * def serviceName = 'TestService'
    * def baseUrl = 'https://httpbin.org'
    * def domainPath = '/anything'
    * def someFlag = true
    * def headers = { 'Content-Type': 'application/json' }
  1. Create a feature file using the snippets below for call read('feature') being called in the main feature's background.
@ignore
Feature: Background call WITHOUT HTTP (control test)

  Scenario:
    * def items = [{ id: 'item1' }, { id: 'item2' }]

Expected Behavior

  1. Each Scenario Outline row gets its own Examples column values. The Background re-executes for each row, and #(fName), #(lName), #(phone) in the request doc-string resolve to the current row's values. Each HTTP request contains distinct data.

Actual Behavior

  1. All rows receive row 1's values. The #() expressions in the doc-string resolve to row 1's column values for every subsequent row

Karate Version

2.1.0

Java Version

25.0.2

Operating System

macOS

Contributor guide