Difference in servers with REST API info and admin page

When I view /admin and look for a user I see their server.

When I use the API with:

curl -s -H “Authorization: token $JUPYTERHUB_API_TOKEN” “$JUPYTERHUB_URL/hub/api/users?offset=0&limit=500” | jq

I don’t see the user.

I think I have full admin rights from a /hub/api/user call I see

{“name”: “mylogin”, “groups”: , “pending”: null, “admin”: true, “created”: “2025-10-22T09:01:37.447462Z”, “server”: null, “last_activity”: “2025-12-24T04:39:33.144959Z”, “auth_state”: null, “roles”: [“user”, “admin”], “kind”: “user”, “servers”: {}, “token_id”: “a4062”, “session_id”: null, “scopes”: [“access:servers”, “access:services”, “admin-ui”, “admin:auth_state”, “admin:groups”, “admin:server_state”, “admin:servers”, “admin:services”, “admin:users”, “delete:groups”, “delete:servers”, “delete:users”, “groups”, “groups:shares”, “list:groups”, “list:services”, “list:users”, “proxy”, “read:groups”, “read:groups:name”, “read:groups:shares”, “read:hub”, “read:metrics”, “read:roles”, “read:roles:groups”, “read:roles:services”, “read:roles:users”, “read:servers”, “read:services”, “read:services:name”, “read:shares”, “read:tokens”, “read:users”, “read:users:activity”, “read:users:groups”, “read:users:name”, “read:users:shares”, “servers”, “shares”, “shutdown”, “tokens”, “users”, “users:activity”, “users:shares”]}

I’m wondering why this is the case? Any ideas on why this could be? It’s 2 users I don’t see with the API call, they definitely do have servers running.

What happens when you attempt to get those two users using API?

1 Like

Thanks for that suggestion, it doesn’t happen all the time so I had to wait for this to occur.

I see a user now in the webui and they have a job (we use the batch/slurmspawner) but not in the API. So I did a query on the one user (removed username and replaced with USER1)

I did a

curl -s
-H “Authorization: token $JUPYTERHUB_API_TOKEN”
“$JUPYTERHUB_URL/hub/api/users/USER1”

result:

{“name”: “USER1”, “groups”: , “pending”: null, “admin”: false, “created”: “2025-11-27T14:35:00.527017Z”, “server”: “/user/USER1/”, “last_activity”: “2025-12-27T02:15:58.968000Z”, “auth_state”: null, “roles”: [“user”], “kind”: “user”, “servers”: {“”: {“name”: “”, “full_name”: “USER1/”, “last_activity”: “2025-12-27T02:15:58.968000Z”, “started”: “2025-12-27T01:22:08.079269Z”, “pending”: null, “ready”: true, “stopped”: false, “url”: “/user/USER1/”, “user_options”: {“profile”: “default”}, “progress_url”: “/hub/api/users/USER1/server/progress”, “full_url”: null, “full_progress_url”: null, “state”: {“child_conf”: {“req_nprocs”: “2”, “req_partition”: “JupyterDev”, “req_runtime”: “14-00:00:00”, “req_memory”: “3048”}, “child_state”: {“job_id”: “12074145”, “job_status”: “RUNNING jupyter-001”}, “profile”: “default”}}}}

It’s not a serious problem for me but it’s just weird the 2 views don’t match

Strange!! One more test you can do is to look into browser console when you visit admin page. Normally JS will make a request to /users endpoint to fetch all the users and verify if those two users are being returned in the response!

Maybe I didn’t say what was happening correctly … They are appearing in the admin page but not when I use the API using a curl so … just curious as to what you were meaning in the above? Can you elaborate or explain what you are suggesting I maybe try? I could also restart the hub to see if things then change if you think that would help, but then it could clear this weird instance and I’d need to then wait for it to reoccur.

The admin panel should make the same API call that you made with curl, but using JavaScript, and this should be visible in your browser console network requests as an API request and the corresponding JSON response.

If you could share the browser console request to the API (including parameters) and response, and from running curl at the same time, that might give us some clues on why there’s a difference, and whether it’s a bug.

1 Like

I’ve done what I think you were after …

I did increase the limit from 50 to 500 so its not that

I did the curl at the same time and it didnt show the user at all, not from the 1st curl anyway

curl -s
-H “Authorization: token $JUPYTERHUB_API_TOKEN”
“$JUPYTERHUB_URL/hub/api/users?include_stopped_servers=1&offset=0&limit=500&name_filter=&sort=id” | jq

it does show the user here

curl -s
-H “Authorization: token $JUPYTERHUB_API_TOKEN”
“$JUPYTERHUB_URL/hub/api/users/sopdeffo”

as per the USER1 result above.

So it seems if I query all users I dont see them but I do if I do just that 1 user

Here you are “searching” your target user and hence in the query parameter name_filter=sopd is used while making the request. What I would suggest is go to Admin page and look for your target user page by page without search functionality.

If I am not wrong, JupyterHub DB uses a lot of in-memory caching and it might be a side effect of caching. Restarting hub can reset things as well if you can do it!

I’m surprised you’re getting a 304 header here, I only ever see 200 responses. Do you have a reverse or caching proxy somewhere?

Here you are “searching” your target user and hence in the query parameter name_filter=sopd is used while making the request. What I would suggest is go to Admin page and look for your target user page by page without search functionality.

if I just hit the admin page https://jupyter/hub/admin#/?limit=250 and if I look (or use the browser Cmd/Ctrl+F) I don’t find the user, if I then click on the user sort ie &sort=name on the URL they then appear. Weird.

I have just restarted the hub now to see what the results were.

No change. Very strange. I’m not really too worried about this as it was only visible when I was doing some tinkering with the API but would be good to figure it out.

Yes, we have a nginx reverse proxy fronting our Jupyterhub instance.

Was showing this to a colleague and he was asking if I was sure I was getting back all users in the query … seems maybe I’m not, I only get 200 back even if I ask for this /hub/api/users?offset=0&limit=500, so could it be that 200 is a hard limit on the server side and the user is actually in the other page.

A better plan he suggested which does work and helps me in this case was to append &state=active to the query, as that’s what I really want, I’m only interested in active servers.

So I think I’m going to do that and not burn more time trying to figure this out more. Thanks for the help and suggestions.

1 Like