gitlabhq/gitlabhq · error · Gitlab::Graphql::Errors::ArgumentError
Non-admin users must provide a groupId, projectId, or curren
Error message
Non-admin users must provide a groupId, projectId, or current username
What it means
The root `timelogs` GraphQL query exposes all time-tracking data, so Resolvers::TimelogResolver#validate_args! requires a scope: a parent object (the field is normally used under a project or group), a `groupId`/`projectId` argument, your own `username`, or admin capability (`can_read_all_resources?`). Without one of these, a non-admin gets ArgumentError with this message. This is a data-exposure guard, not a syntax check.
Source
Thrown at app/graphql/resolvers/timelog_resolver.rb:118
def parse_datetime_args(args)
if times_provided?(args)
args
else
parsed_args = args.except(:start_date, :end_date)
parsed_args[:start_time] = args[:start_date].beginning_of_day if args[:start_date]
parsed_args[:end_time] = args[:end_date].end_of_day if args[:end_date]
parsed_args
end
end
def times_provided?(args)
args[:start_time] && args[:end_time]
end
def raise_argument_error(message)
raise Gitlab::Graphql::Errors::ArgumentError, message
end
end
end
View on GitHub (pinned to 55ee20384a)
Solutions
- Add a scope argument to the query: `groupId`, `projectId`, or your own `username`
- If instance-wide timelogs are genuinely needed, use an account with admin read access (custom admin role with can_read_all_resources) — otherwise scope per group/project
- If you intended your own timelogs, set `username` to exactly your authenticated user's username
Example fix
# before
query {
timelogs(startDate: "2026-08-01") { nodes { timeSpent user { username } } }
}
# after
query {
timelogs(
startDate: "2026-08-01"
groupId: "gid://gitlab/Group/507"
) { nodes { timeSpent user { username } } }
} Defensive patterns
Strategy: validation
Validate before calling
function assertTimelogScope(args, currentUser) {
const scoped = args.groupId || args.projectId ||
(args.username && args.username === currentUser?.username);
if (!scoped && !currentUser?.admin) {
throw new Error('timelogs: non-admin must pass groupId, projectId, or own username');
}
} Type guard
function isScopedTimelogQuery(args, currentUser) {
return Boolean(args.groupId ?? args.projectId ?? (args.username === currentUser?.username));
} Try / catch
catch (err) {
if (err.graphqlErrors?.some(e => e.message.startsWith('Non-admin users must provide'))) {
promptUserToPickGroupOrProject(); // degrade to scoped query UI
}
} Prevention
- Default your timelog UI to a selected group/project rather than instance-wide
- Detect loss of admin rights at token-refresh time, not at query time
When it happens
Trigger: `query { timelogs(startDate: ...) { nodes { timeSpent } } }` at the root with no groupId/projectId/username; passing another user's username while not being an admin; a script that worked under an admin token then run with a regular PAT.
Common situations: Personal access tokens swapped from admin to non-admin during a security cleanup; dashboards ported from the REST timelog endpoints that defaulted to instance-wide data; forgetting the scope argument when moving from the group-scoped field to the root query.
Related errors
- Provide either a start date or time, but not both
- Provide either an end date or time, but not both
- locked is not a valid state filter for issues.
- You cannot provide more than 50 full_paths
- Filtering by both an author and a project is not supported
AI-assisted analysis of gitlabhq/gitlabhq@55ee20384a (2026-08-21).
Data as JSON: /api/errors/18e4b308fa1cd34b.
Report an issue: GitHub.