{"record":{"id":"92a6f6ca44c6a6bb","repo":"stablyai/orca","slug":"project-name-is-required","errorCode":null,"errorMessage":"Project name is required","messagePattern":"Project name is required","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/linear/projects.ts","lineNumber":894,"sourceCode":"      >(trimmed ? SEARCH_PROJECTS_QUERY : PROJECTS_QUERY, variables)\n      const connection = trimmed ? result.data?.searchProjects : result.data?.projects\n      return {\n        items: (connection?.nodes ?? []).map((project) => mapProjectForWorkspace(entry, project)),\n        hasMore: !!connection?.pageInfo?.hasNextPage\n      }\n    },\n    force\n  )\n}\n\nexport async function listProjectsByExactName(\n  name: string,\n  workspaceId: LinearConcreteWorkspaceId,\n  force = false\n): Promise<LinearProjectSummary[]> {\n  const projectName = name.trim()\n  if (!projectName) {\n    throw new Error('Project name is required')\n  }\n  const normalized = projectName.toLowerCase()\n  const concreteWorkspaceId = normalizeConcreteWorkspaceId(workspaceId)\n  const key = `listProjectsByExactName:${concreteWorkspaceId}:${normalized}`\n  return coalesce(\n    key,\n    async () => {\n      const entries = getClients(concreteWorkspaceId)\n      const entry = entries[0]\n      if (!entry) {\n        return []\n      }\n      await acquire()\n      try {\n        const matches: LinearProjectSummary[] = []\n        let after: string | undefined\n        while (true) {\n          const result = await entry.client.client.rawRequest<","sourceCodeStart":876,"sourceCodeEnd":912,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/src/main/linear/projects.ts#L876-L912","documentation":"Thrown by listProjectsByExactName when the trimmed name is empty. The exact-name lookup needs a non-blank search term; an empty term is rejected before any Linear call. It is a plain Error.","triggerScenarios":"Calling listProjectsByExactName('', ws), listProjectsByExactName('   ', ws), or with a name that becomes empty after trim.","commonSituations":"Caller passed an unvalidated input-field value; whitespace-only name from a form; programmatic lookup with an undefined coerced to string.","solutions":["Trim and validate the name is non-empty at the call site before invoking.","Return an empty result instead of calling the API when the trimmed name is empty.","Guard the UI submit handler to disable lookup on blank input."],"exampleFix":"// before\nconst projects = await listProjectsByExactName(rawName, workspaceId)\n// after\nconst name = rawName.trim()\nif (!name) return []\nconst projects = await listProjectsByExactName(name, workspaceId)","handlingStrategy":"validation","validationCode":"const name = rawName.trim()\nif (!name) return [] // or throw new Error('Project name is required')","typeGuard":"function isNonEmptyName(name: unknown): name is string {\n  return typeof name === 'string' && name.trim().length > 0\n}","tryCatchPattern":"try { await listProjectsByExactName(name, workspaceId) }\ncatch (e) { if (e instanceof Error && e.message === 'Project name is required') return [] else throw e }","preventionTips":["Trim and check the name at the call site before invoking.","Disable lookup UI actions on blank input.","Return early for empty names rather than hitting the API."],"tags":["linear","validation","projects","input"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}