<h3 dir="auto">Apache Airflow version</h3>
<p dir="auto">2.3.2 (latest released)</p>
<h3 dir="auto">What happened</h3>
<p dir="auto">Using the provided minimal example, <code class="notranslate">task_instance</code> (i.e., <code class="notranslate">ti</code>) is accessible when using <code class="notranslate">PythonOperator</code> but fails when using <code class="notranslate">PythonVirtualenvOperator</code>.</p>
<h3 dir="auto">What you think should happen instead</h3>
<p dir="auto">I would expect <code class="notranslate">PythonOperator</code> and <code class="notranslate">PythonVirtualenvOperator</code> to behave in a similar way. Instead, none of the xcom examples work with <code class="notranslate">PythonVirtualenvOperator</code>.</p>
<h3 dir="auto">How to reproduce</h3>
<p dir="auto">Switch between <code class="notranslate">PythonOperator</code> and <code class="notranslate">PythonVirtualenvOperator</code>. Using <code class="notranslate">PythonVirtualenvOperator</code> dag will fail.</p>
<div class="highlight highlight-source-python notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="from airflow import DAG
from airflow.operators.python import PythonVirtualenvOperator, PythonOperator
from datetime import datetime, timedelta

def _pusher(ti):
    ti.xcom_push(key='my-key', value='my-value')

def _puller(ti):
    value = ti.xcom_pull(task_ids='pusher', key='my-key')
    assert value == 'my-value'

with DAG('minimal-example', schedule_interval='@once', start_date=datetime(2021, 1, 1), catchup=False) as dag:
    #pusher = PythonVirtualenvOperator(
    pusher = PythonOperator(
        task_id='pusher',
        python_callable=_pusher,
        #requirements=[],
    )

    #puller = PythonVirtualenvOperator(
    puller = PythonOperator(
        task_id='puller',
        python_callable=_puller,
        #requirements=[],
    )

    pusher &gt;&gt; puller"><pre class="notranslate"><span class="pl-k">from</span> <span class="pl-s1">airflow</span> <span class="pl-k">import</span> <span class="pl-v">DAG</span>
<span class="pl-k">from</span> <span class="pl-s1">airflow</span>.<span class="pl-s1">operators</span>.<span class="pl-s1">python</span> <span class="pl-k">import</span> <span class="pl-v">PythonVirtualenvOperator</span>, <span class="pl-v">PythonOperator</span>
<span class="pl-k">from</span> <span class="pl-s1">datetime</span> <span class="pl-k">import</span> <span class="pl-s1">datetime</span>, <span class="pl-s1">timedelta</span>

<span class="pl-k">def</span> <span class="pl-en">_pusher</span>(<span class="pl-s1">ti</span>):
    <span class="pl-s1">ti</span>.<span class="pl-en">xcom_push</span>(<span class="pl-s1">key</span><span class="pl-c1">=</span><span class="pl-s">'my-key'</span>, <span class="pl-s1">value</span><span class="pl-c1">=</span><span class="pl-s">'my-value'</span>)

<span class="pl-k">def</span> <span class="pl-en">_puller</span>(<span class="pl-s1">ti</span>):
    <span class="pl-s1">value</span> <span class="pl-c1">=</span> <span class="pl-s1">ti</span>.<span class="pl-en">xcom_pull</span>(<span class="pl-s1">task_ids</span><span class="pl-c1">=</span><span class="pl-s">'pusher'</span>, <span class="pl-s1">key</span><span class="pl-c1">=</span><span class="pl-s">'my-key'</span>)
    <span class="pl-k">assert</span> <span class="pl-s1">value</span> <span class="pl-c1">==</span> <span class="pl-s">'my-value'</span>

<span class="pl-k">with</span> <span class="pl-v">DAG</span>(<span class="pl-s">'minimal-example'</span>, <span class="pl-s1">schedule_interval</span><span class="pl-c1">=</span><span class="pl-s">'@once'</span>, <span class="pl-s1">start_date</span><span class="pl-c1">=</span><span class="pl-en">datetime</span>(<span class="pl-c1">2021</span>, <span class="pl-c1">1</span>, <span class="pl-c1">1</span>), <span class="pl-s1">catchup</span><span class="pl-c1">=</span><span class="pl-c1">False</span>) <span class="pl-k">as</span> <span class="pl-s1">dag</span>:
    <span class="pl-c">#pusher = PythonVirtualenvOperator(</span>
    <span class="pl-s1">pusher</span> <span class="pl-c1">=</span> <span class="pl-v">PythonOperator</span>(
        <span class="pl-s1">task_id</span><span class="pl-c1">=</span><span class="pl-s">'pusher'</span>,
        <span class="pl-s1">python_callable</span><span class="pl-c1">=</span><span class="pl-s1">_pusher</span>,
        <span class="pl-c">#requirements=[],</span>
    )

    <span class="pl-c">#puller = PythonVirtualenvOperator(</span>
    <span class="pl-s1">puller</span> <span class="pl-c1">=</span> <span class="pl-v">PythonOperator</span>(
        <span class="pl-s1">task_id</span><span class="pl-c1">=</span><span class="pl-s">'puller'</span>,
        <span class="pl-s1">python_callable</span><span class="pl-c1">=</span><span class="pl-s1">_puller</span>,
        <span class="pl-c">#requirements=[],</span>
    )

    <span class="pl-s1">pusher</span> <span class="pl-c1">&gt;&gt;</span> <span class="pl-s1">puller</span></pre></div>
<h3 dir="auto">Operating System</h3>
<p dir="auto">Ubuntu 20.04</p>
<h3 dir="auto">Versions of Apache Airflow Providers</h3>
<p dir="auto">Apache airflow 2.3.2 in docker container</p>
<h3 dir="auto">Deployment</h3>
<p dir="auto">Docker-Compose</p>
<h3 dir="auto">Deployment details</h3>
<p dir="auto"><a href="https://github.com/apache/airflow/blob/2.3.2/docs/apache-airflow/start/docker-compose.yaml">https://github.com/apache/airflow/blob/2.3.2/docs/apache-airflow/start/docker-compose.yaml</a></p>
<h3 dir="auto">Anything else</h3>
<p dir="auto"><em>No response</em></p>
<h3 dir="auto">Are you willing to submit PR?</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox"> Yes I am willing to submit a PR!</li>
</ul>
<h3 dir="auto">Code of Conduct</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> I agree to follow this project's <a href="https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md">Code of Conduct</a></li>
</ul>
<p dir="auto"><strong>Apache Airflow version</strong>: 1.10.13</p>
<p dir="auto"><strong>Environment</strong>: Docker (Ubuntu 18.4 - Python 3.7)</p>
<ul dir="auto">
<li>Cloud provider or hardware configuration: Azure</li>
<li>OS (e.g. from /etc/os-release): Docker (Ubuntu 18.4 - Python 3.7)</li>
<li>Kernel (e.g. uname -a): Docker (Ubuntu 18.4 - Python 3.7)</li>
<li>Install tools: N/A</li>
<li>Others: N/A</li>
</ul>
<p dir="auto"><strong>What happened:</strong></p>
<p dir="auto">When we enable provide_context=True for PythonVirtualenvOperator and try to use the xcom_push to pass a variable I get this error:</p>
<p dir="auto"><code class="notranslate">File "/tmp/venv0upgqome/script.py", line 13, in push\n    kwargs[\'ti\'].xcom_push(key=\'value from pusher 1\', value=value_1)\nKeyError: \'ti\'\n'</code></p>
<p dir="auto"><strong>How to reproduce it:</strong></p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="import airflow
from airflow import DAG
from airflow.operators.python_operator import PythonVirtualenvOperator

args = {
    'owner': 'Airflow',
    'start_date': airflow.utils.dates.days_ago(2),

}

dag = DAG('BAtatas', schedule_interval=&quot;@once&quot;, default_args=args)


def push(**kwargs):
    &quot;&quot;&quot;Pushes an XCom without a specific target&quot;&quot;&quot;
    value_1 = [1, 2, 3]
    print(&quot;printing the kwargs!!!&quot;)
    print(kwargs)
    kwargs['ti'].xcom_push(key='value from pusher 1', value=value_1)


def push_by_returning(**kwargs):
    value_2 = {'a': 'b'}
    &quot;&quot;&quot;Pushes an XCom without a specific target, just by returning it&quot;&quot;&quot;
    return value_2


def puller(**kwargs):
    value_2 = {'a': 'b'}
    value_1 = [1, 2, 3]
    &quot;&quot;&quot;Pull all previously pushed XComs and check if the pushed values match the pulled values.&quot;&quot;&quot;
    ti = kwargs['ti']

    # get value_1
    pulled_value_1 = ti.xcom_pull(key=None, task_ids='push')
    assert pulled_value_1 == value_1

    # get value_2
    pulled_value_2 = ti.xcom_pull(task_ids='push_by_returning')
    assert pulled_value_2 == value_2

    # get both value_1 and value_2
    pulled_value_1, pulled_value_2 = ti.xcom_pull(
        key=None, task_ids=['push', 'push_by_returning'])
    assert (pulled_value_1, pulled_value_2) == (value_1, value_2)


push1 = PythonVirtualenvOperator(
    task_id='push',
    dag=dag,
    python_callable=push,
    requirements=[],
    python_version='3.7',
    use_dill=False,
    provide_context=True,
    system_site_packages=True,

)

push2 = PythonVirtualenvOperator(
    task_id='push_by_returning',
    dag=dag,
    python_callable=push_by_returning,
    requirements=[],
    python_version='3.7',
    use_dill=False,
    provide_context=True,
    system_site_packages=True,

)

pull = PythonVirtualenvOperator(
    task_id='puller',
    dag=dag,
    python_callable=puller,
    requirements=[],
    python_version='3.7',
    use_dill=False,
    provide_context=True,
    system_site_packages=True,

)

pull &lt;&lt; [push1, push2]"><pre class="notranslate"><code class="notranslate">import airflow
from airflow import DAG
from airflow.operators.python_operator import PythonVirtualenvOperator

args = {
    'owner': 'Airflow',
    'start_date': airflow.utils.dates.days_ago(2),

}

dag = DAG('BAtatas', schedule_interval="@once", default_args=args)


def push(**kwargs):
    """Pushes an XCom without a specific target"""
    value_1 = [1, 2, 3]
    print("printing the kwargs!!!")
    print(kwargs)
    kwargs['ti'].xcom_push(key='value from pusher 1', value=value_1)


def push_by_returning(**kwargs):
    value_2 = {'a': 'b'}
    """Pushes an XCom without a specific target, just by returning it"""
    return value_2


def puller(**kwargs):
    value_2 = {'a': 'b'}
    value_1 = [1, 2, 3]
    """Pull all previously pushed XComs and check if the pushed values match the pulled values."""
    ti = kwargs['ti']

    # get value_1
    pulled_value_1 = ti.xcom_pull(key=None, task_ids='push')
    assert pulled_value_1 == value_1

    # get value_2
    pulled_value_2 = ti.xcom_pull(task_ids='push_by_returning')
    assert pulled_value_2 == value_2

    # get both value_1 and value_2
    pulled_value_1, pulled_value_2 = ti.xcom_pull(
        key=None, task_ids=['push', 'push_by_returning'])
    assert (pulled_value_1, pulled_value_2) == (value_1, value_2)


push1 = PythonVirtualenvOperator(
    task_id='push',
    dag=dag,
    python_callable=push,
    requirements=[],
    python_version='3.7',
    use_dill=False,
    provide_context=True,
    system_site_packages=True,

)

push2 = PythonVirtualenvOperator(
    task_id='push_by_returning',
    dag=dag,
    python_callable=push_by_returning,
    requirements=[],
    python_version='3.7',
    use_dill=False,
    provide_context=True,
    system_site_packages=True,

)

pull = PythonVirtualenvOperator(
    task_id='puller',
    dag=dag,
    python_callable=puller,
    requirements=[],
    python_version='3.7',
    use_dill=False,
    provide_context=True,
    system_site_packages=True,

)

pull &lt;&lt; [push1, push2]
</code></pre></div>