{"record":{"id":"bb11ff76e1ff3281","repo":"garrytan/gstack","slug":"each-cookie-must-have-name-and-value-fields","errorCode":null,"errorMessage":"Each cookie must have \"name\" and \"value\" fields","messagePattern":"Each cookie must have \"name\" and \"value\" fields","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"browse/src/write-commands.ts","lineNumber":668,"sourceCode":"      try { resolvedReal = fs.realpathSync(resolved); } catch {\n        // File may not exist yet — resolve parent dir instead\n        try { resolvedReal = path.join(fs.realpathSync(path.dirname(resolved)), path.basename(resolved)); } catch {}\n      }\n      if (!SAFE_DIRECTORIES.some(dir => isPathWithin(resolvedReal, dir))) {\n        throw new Error(`Path must be within: ${SAFE_DIRECTORIES.join(', ')}`);\n      }\n      if (!fs.existsSync(filePath)) throw new Error(`File not found: ${filePath}`);\n      const raw = fs.readFileSync(filePath, 'utf-8');\n      let cookies: any[];\n      try { cookies = JSON.parse(raw); } catch (err: any) { throw new Error(`Invalid JSON in ${filePath}: ${err?.message || err}`); }\n      if (!Array.isArray(cookies)) throw new Error('Cookie file must contain a JSON array');\n\n      // Auto-fill domain from current page URL when missing (consistent with cookie command)\n      const pageUrl = new URL(page.url());\n      const defaultDomain = pageUrl.hostname;\n\n      for (const c of cookies) {\n        if (!c.name || c.value === undefined) throw new Error('Each cookie must have \"name\" and \"value\" fields');\n        if (!c.domain) {\n          c.domain = defaultDomain;\n        } else {\n          const cookieDomain = c.domain.startsWith('.') ? c.domain.slice(1) : c.domain;\n          if (cookieDomain !== defaultDomain && !defaultDomain.endsWith('.' + cookieDomain)) {\n            throw new Error(`Cookie domain \"${c.domain}\" does not match current page domain \"${defaultDomain}\". Use the target site first.`);\n          }\n        }\n        if (!c.path) c.path = '/';\n      }\n\n      await page.context().addCookies(cookies);\n      const importedDomains = [...new Set(cookies.map((c: any) => c.domain).filter(Boolean))];\n      if (importedDomains.length > 0) bm.trackCookieImportDomains(importedDomains);\n      return `Loaded ${cookies.length} cookies from ${filePath}`;\n    }\n\n    case 'cookie-import-browser': {","sourceCodeStart":650,"sourceCodeEnd":686,"githubUrl":"https://github.com/garrytan/gstack/blob/94993f74012782fd94416dd44b8314f6363a13a4/browse/src/write-commands.ts#L650-L686","documentation":"Thrown by `browse cookie-import` inside the per-cookie validation loop when a cookie object lacks a `name` field or has `value === undefined`. Playwright's `addCookies` requires both, so the command rejects the entire batch on the first malformed entry rather than letting Playwright throw an opaque error mid-import. Note `value: ''` (empty string) is accepted — only `undefined` is rejected.","triggerScenarios":"A cookie object shaped as `{ name: 'x' }` (value missing), `{ value: 'y' }` (name missing), `{ n: 'x', v: 'y' }` (wrong keys from a Netscape column mapping), or a string element in the array instead of an object.","commonSituations":"Export tool used different field names (`cookie_name` vs `name`); a Netscape-to-JSON converter mapped columns wrong; a hand-built cookie array omitted `value` for flag-only cookies; an LLM-generated cookie JSON used `\"value\"` as the key but left it null.","solutions":["Ensure each cookie object has both `name` (truthy string) and `value` (defined, may be empty string) fields.","If your source uses different keys, map them: `cookies.map(c => ({ name: c.cookie_name, value: c.cookie_value ?? '', domain: c.domain, path: c.path }))`.","Validate the array shape before importing: every element must be an object with `name` and `value`.","Use Playwright's own `context.cookies()` export as the canonical shape reference."],"exampleFix":"// before\nconst cookies = [{ name: 'sid' }, { name: 'csrf', value: 'abc' }];\nfs.writeFileSync(fp, JSON.stringify(cookies));\nawait runBrowseCommand(['cookie-import', fp]);\n\n// after\nconst cookies = [{ name: 'sid', value: 'x', domain: 'example.com', path: '/' }, { name: 'csrf', value: 'abc', domain: 'example.com', path: '/' }];\nfs.writeFileSync(fp, JSON.stringify(cookies));\nawait runBrowseCommand(['cookie-import', fp]);","handlingStrategy":"type-guard","validationCode":"function validateCookieShape(cookies: unknown[]): void {\n  cookies.forEach((c, i) => {\n    if (typeof c !== 'object' || c === null || !('name' in c) || !('value' in c) || (c as any).value === undefined) {\n      throw new Error(`cookies[${i}] must have name and value fields`);\n    }\n  });\n}","typeGuard":"function isCookieObject(v: unknown): v is { name: string; value: string; domain?: string; path?: string } {\n  return typeof v === 'object' && v !== null && typeof (v as any).name === 'string' && (v as any).name.length > 0 && 'value' in v && (v as any).value !== undefined;\n}","tryCatchPattern":null,"preventionTips":["Map source fields to {name, value} before importing.","Note empty-string value is allowed; only undefined is rejected.","Validate the array shape before passing to cookie-import."],"tags":["cookies","import","validation","data-shape","browse-command"],"backgroundTag":null,"analyzedSha":"94993f74012782fd94416dd44b8314f6363a13a4","analyzedAt":"2026-08-12T04:06:23.140Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}