{"record":{"id":"18e4b308fa1cd34b","repo":"gitlabhq/gitlabhq","slug":"non-admin-users-must-provide-a-groupid-projectid","errorCode":null,"errorMessage":"Non-admin users must provide a groupId, projectId, or current username","messagePattern":"Non-admin users must provide a groupId, projectId, or current username","errorType":"validation","errorClass":"Gitlab::Graphql::Errors::ArgumentError","httpStatus":null,"severity":"error","filePath":"app/graphql/resolvers/timelog_resolver.rb","lineNumber":118,"sourceCode":"    def parse_datetime_args(args)\n      if times_provided?(args)\n        args\n      else\n        parsed_args = args.except(:start_date, :end_date)\n\n        parsed_args[:start_time] = args[:start_date].beginning_of_day if args[:start_date]\n        parsed_args[:end_time] = args[:end_date].end_of_day if args[:end_date]\n\n        parsed_args\n      end\n    end\n\n    def times_provided?(args)\n      args[:start_time] && args[:end_time]\n    end\n\n    def raise_argument_error(message)\n      raise Gitlab::Graphql::Errors::ArgumentError, message\n    end\n  end\nend\n","sourceCodeStart":100,"sourceCodeEnd":122,"githubUrl":"https://github.com/gitlabhq/gitlabhq/blob/55ee20384a1f55cb0e362dee1d07149613b1b9bf/app/graphql/resolvers/timelog_resolver.rb#L100-L122","documentation":"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.","triggerScenarios":"`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.","commonSituations":"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.","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"],"exampleFix":"# before\nquery {\n  timelogs(startDate: \"2026-08-01\") { nodes { timeSpent user { username } } }\n}\n\n# after\nquery {\n  timelogs(\n    startDate: \"2026-08-01\"\n    groupId: \"gid://gitlab/Group/507\"\n  ) { nodes { timeSpent user { username } } }\n}","handlingStrategy":"validation","validationCode":"function assertTimelogScope(args, currentUser) {\n  const scoped = args.groupId || args.projectId ||\n    (args.username && args.username === currentUser?.username);\n  if (!scoped && !currentUser?.admin) {\n    throw new Error('timelogs: non-admin must pass groupId, projectId, or own username');\n  }\n}","typeGuard":"function isScopedTimelogQuery(args, currentUser) {\n  return Boolean(args.groupId ?? args.projectId ?? (args.username === currentUser?.username));\n}","tryCatchPattern":"catch (err) {\n  if (err.graphqlErrors?.some(e => e.message.startsWith('Non-admin users must provide'))) {\n    promptUserToPickGroupOrProject(); // degrade to scoped query UI\n  }\n}","preventionTips":["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"],"tags":["graphql","timelogs","authorization","argument-validation","gitlab-api"],"backgroundTag":"graphql-authorization-scope-required","analyzedSha":"55ee20384a1f55cb0e362dee1d07149613b1b9bf","analyzedAt":"2026-08-21T14:22:27.782Z","schemaVersion":2},"datasetVersion":"2026-08-21T18:17:14.833Z"}