prefect icon indicating copy to clipboard operation
prefect copied to clipboard

read_work_queue_by_name raises JSONDecodeError

Open apolisskaya opened this issue 2 years ago • 3 comments

First check

  • [X] I added a descriptive title to this issue.
  • [X] I used the GitHub search to find a similar issue and didn't find it.
  • [X] I searched the Prefect documentation for this issue.
  • [X] I checked that this issue is related to Prefect and not one of its dependencies.

Bug summary

client: OrionClient queue_name: "sync_assessments"

When running the following, raises JSONDecodeError:

work_queue = await client.read_work_queue_by_name(queue_name)

Referencing the Prefect source code and stepping through the execution with pdb: response = await self._client.get(f"/work_queues/name/{name}") -> returns a 200 OK with response.is_success == True and response.text looks like

'<!DOCTYPE html>\n<html lang="en">\n  <head>\n    <meta http-equiv="Cache-Control" content="max-age=0, must-revalidate"/>\n    <meta http-equiv="Pragma" content="no-cache"/>\n    <meta http-equiv="Expires" content="0" />\n    <meta charset="UTF-8" />\n    <link rel="apple-touch-icon" sizes="180x180" href="/ico/apple-touch-icon.png">\n  \n    <link rel="icon" id="favicon-32" type="image/png" sizes="32x32" href="/ico/favicon-32x32.png" media="(prefers-color-scheme:light)">\n    <link rel="icon" id="favicon-16" type="image/png" sizes="16x16" href="/ico/favicon-16x16.png" media="(prefers-color-scheme:light)">\n\n    <link rel="icon" id="favicon-32-dark" type="image/png" sizes="32x32" href="/ico/favicon-32x32-dark.png" media="(prefers-color-scheme:dark)">\n    <link rel="icon" id="favicon-16-dark" type="image/png" sizes="16x16" href="/ico/favicon-16x16-dark.png" media="(prefers-color-scheme:dark)">\n\n    <link rel="icon" href="/favicon.ico" media="(prefers-color-scheme:no-preference)">\n    <link rel="icon" href="/favicon.ico" media="(prefers-color-scheme:light)">\n    <link rel="icon" href="/favicon-dark.ico" media="(prefers-color-scheme:dark)">\n\n    <link rel="manifest" href="/ico/site.webmanifest">\n    <link rel="mask-icon" href="/ico/safari-pinned-tab.svg" color="#5bbad5">\n    <meta name="msapplication-TileColor" content="#da532c">\n    <meta name="theme-color" content="#ffffff">\n\n    <script src="/registerSW.js"></script>\n\n    <!-- https://stripe.com/docs/payments/quickstart -->\n    <!-- Don’t include the script in a bundle or host it yourself. -->\n    <script src="https://js.stripe.com/v3/"></script>\n\n    <meta name="viewport" content="width=device-width, initial-scale=1.0" />\n    <title>Prefect Cloud</title>\n    <script type="module" crossorigin src="/index.50a5a629.js"></script>\n    <link rel="stylesheet" href="/assets/index-18768f53.css">\n  </head>\n  <body>\n    <div id="app"></div>\n    \n  </body>\n</html>\n'

which is definitely not valid JSON, so the return statement which looks like return WorkQueue.parse_obj(response.json()) is raising json.decoder.JSONDecodeError

Reproduction

Using `OrionClient` and any string as `queue_name`, make a call to `read_work_queue_by_name`

Error

This was reported by an engineer on our team with the following stack trace:


Traceback (most recent call last):
 File "/Users/cwatts/Code/api/manage.py", line 31, in <module>
  execute_from_command_line(sys.argv)
 File "/Users/cwatts/.local/share/virtualenvs/api-mwSkRMLi/lib/python3.9/site-packages/django/core/management/__init__.py", line 446, in execute_from_command_line
  utility.execute()
 File "/Users/cwatts/.local/share/virtualenvs/api-mwSkRMLi/lib/python3.9/site-packages/django/core/management/__init__.py", line 440, in execute
  self.fetch_command(subcommand).run_from_argv(self.argv)
 File "/Users/cwatts/.local/share/virtualenvs/api-mwSkRMLi/lib/python3.9/site-packages/django/core/management/base.py", line 402, in run_from_argv
  self.execute(*args, **cmd_options)
 File "/Users/cwatts/.local/share/virtualenvs/api-mwSkRMLi/lib/python3.9/site-packages/django/core/management/base.py", line 448, in execute
  output = self.handle(*args, **options)
 File "/Users/cwatts/Code/api/octave_core/management/commands/prefect.py", line 96, in handle
  asyncio.run(self.register(flow_groups))
 File "/usr/local/Cellar/[email protected]/3.9.17/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/runners.py", line 44, in run
  return loop.run_until_complete(main)
 File "/usr/local/Cellar/[email protected]/3.9.17/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 647, in run_until_complete
  return future.result()
 File "/Users/cwatts/Code/api/octave_core/management/commands/prefect.py", line 120, in register
  await flow_group.create_flow_deployments(tags=["agent:octave-core"])
 File "/Users/cwatts/Code/api/octave_core/prefect/flows/__init__.py", line 196, in create_flow_deployments
  deployment_ids.update(set(await flow_info.create_deployments(client, tags=deployment_tags.copy())))
 File "/Users/cwatts/Code/api/octave_core/prefect/flows/flow_info.py", line 21, in create_deployments
  deployment_id = await deploy.create_for_flow(
 File "/Users/cwatts/Code/api/octave_core/prefect/flows/deployment.py", line 128, in create_for_flow
  work_queue = await client.read_work_queue_by_name(self.queue)
 File "/Users/cwatts/.local/share/virtualenvs/api-mwSkRMLi/lib/python3.9/site-packages/prefect/client/orchestration.py", line 920, in read_work_queue_by_name
  return WorkQueue.parse_obj(response.json())
 File "/Users/cwatts/.local/share/virtualenvs/api-mwSkRMLi/lib/python3.9/site-packages/httpx/_models.py", line 756, in json
  return jsonlib.loads(self.text, **kwargs)
 File "/usr/local/Cellar/[email protected]/3.9.17/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/__init__.py", line 346, in loads
  return _default_decoder.decode(s)
 File "/usr/local/Cellar/[email protected]/3.9.17/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/decoder.py", line 337, in decode
  obj, end = self.raw_decode(s, idx=_w(s, 0).end())
 File "/usr/local/Cellar/[email protected]/3.9.17/Frameworks/Python.framework/Versions/3.9/lib/python3.9/json/decoder.py", line 355, in raw_decode
  raise JSONDecodeError("Expecting value", s, err.value) from None
json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)


### Versions

```Text
--- % prefect version
Version:             2.11.0
API version:         0.8.4
Python version:      3.9.16
Git commit:          eeb9e219
Built:               Thu, Jul 20, 2023 4:34 PM
OS/Arch:             darwin/arm64
Profile:             default
Server type:         server


### Additional context

_No response_

apolisskaya avatar Jul 28 '23 17:07 apolisskaya

I haven't reproduced this so first step for whoever picks it up is to check you can reproduce and add more details.

zhen0 avatar Aug 01 '23 14:08 zhen0

You should include /api in PREFECT_API_URL, e.g. export PREFECT_API_URL=http://127.0.0.1:4200/api

Wh1isper avatar Nov 27 '24 09:11 Wh1isper

Facing the same issue when trying to use prefect behind nginx (via reverse proxy)

Following is my nginx conf:

upstream prefect_server {
    server server:4200;
}

# now we declare our main server
server {

    listen 80;
    server_name _;
    client_max_body_size 10M;

    location /prefect/api {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        rewrite ^/prefect/api/?(.*)$ /api/$1 break;
        proxy_pass http://prefect_server;
    }
    location /prefect/ {
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
        proxy_redirect off;
        proxy_pass http://prefect_server;
    }
}

Following is the compose.yaml:

services:
  ### Prefect Database
  database:
    image: postgres:alpine
    restart: always
    environment:
      - POSTGRES_USER=${POSTGRES_USER}
      - POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
      - POSTGRES_DB=${POSTGRES_DB}
    networks:
      - prefect_network
    volumes:
      - ./data/db:/var/lib/postgresql/data

  ### Nginx Reverse Proxy
  nginx:
    image: nginx:alpine
    restart: always
    ports:
      - 8000:80
    networks:
      - ui_network
    volumes:
      - ./config/nginx/:/etc/nginx/conf.d/
    depends_on:
      - server

  ### Prefect Server API and UI
  server:
    image: prefecthq/prefect:3-python3.12
    restart: always
    volumes:
      - prefect:/root/.prefect
    entrypoint: ["/opt/prefect/entrypoint.sh", "prefect", "server", "start"]
    environment:
      - PREFECT_UI_URL=http://0.0.0.0:8000/prefect
      - PREFECT_API_URL=/prefect/api
      - PREFECT_UI_SERVE_BASE=/prefect
      # If you want to access Prefect Server UI from anywhere other than the Docker host machine, you will need to change
      # PREFECT_UI_URL and PREFECT_API_URL to match the external hostname/IP of the host machine. For example:
      #- PREFECT_UI_URL=http://external-ip/prefect
      #- PREFECT_API_URL=http://external-ip/prefect/api
      - PREFECT_SERVER_API_HOST=${PREFECT_SERVER_API_HOST}
      - PREFECT_API_DATABASE_CONNECTION_URL=${PREFECT_API_DATABASE_CONNECTION_URL}
      # - EXTRA_PIP_PACKAGES=${EXTRA_PIP_PACKAGES}
    depends_on:
      - database
    networks:
      - ui_network
      - prefect_network

  ### Auto-discovery and deployment service
  deploy:
    image: prefecthq/prefect:3-python3.12
    restart: "no"
    working_dir: "/root/flows"
    volumes:
      - "./flows:/root/flows"
      - "./deployments:/root/deployments"
    environment:
      # - PREFECT_API_URL=${PREFECT_API_URL:-http://0.0.0.0:8000/prefect/api}
      - PREFECT_API_URL=http://server:4200/prefect/api
      - WORK_POOL_NAME=${WORK_POOL_NAME}
      - WORK_POOL_TYPE=${WORK_POOL_TYPE}
    depends_on:
      - server
    networks:
      - prefect_network
    entrypoint:
      - bash
      - -c
      - |
        echo 'Waiting for Prefect server to be ready...'
        sleep 30
        echo 'Creating work pool...'
        prefect work-pool create $${WORK_POOL_NAME} --type $${WORK_POOL_TYPE} || echo 'Work pool already exists'

  ## Prefect Worker (Process-based for local execution)
  worker:
    image: prefecthq/prefect:3-python3.12
    restart: always
    entrypoint:
      [
        "/opt/prefect/entrypoint.sh",
        "prefect",
        "worker",
        "start",
        "--pool",
        "${WORK_POOL_NAME}",
        "--type",
        "${WORK_POOL_TYPE}",
      ]
    environment:
      - PREFECT_API_URL=http://server:4200/prefect/api
      # - PREFECT_API_URL=${PREFECT_API_URL:-http://0.0.0.0:8000/prefect/api}
      # - EXTRA_PIP_PACKAGES=${EXTRA_PIP_PACKAGES}
    networks:
      - prefect_network
    volumes:
      - ./flows:/root/flows
    depends_on:
      - deploy

volumes:
  prefect:

networks:
  ui_network:
  prefect_network:

Pk13055 avatar May 27 '25 09:05 Pk13055

You should include /api in PREFECT_API_URL, e.g. export PREFECT_API_URL=http://127.0.0.1:4200/api

THIS SHOULD BE PLACED AT THE TOP OF THE DOCUMENTATION. 😠

szthanatos avatar Jul 22 '25 03:07 szthanatos

OMG, just wasted 3 hours and all I needed was /api !!!!

anengineerdude avatar Oct 20 '25 13:10 anengineerdude