{"record":{"id":"616cd557bc8c5eb8","repo":"evanw/esbuild","slug":"key-quote-key-in-object-quote-property-mus","errorCode":null,"errorMessage":"key ${quote(key)} in object ${quote(property)} must be a string","messagePattern":"key (.+?) in object (.+?) must be a string","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"lib/shared/common.ts","lineNumber":1826,"sourceCode":"  }\n\n  return messagesClone\n}\n\nfunction sanitizeStringArray(values: any[], property: string): string[] {\n  const result: string[] = []\n  for (const value of values) {\n    if (typeof value !== 'string') throw new Error(`${quote(property)} must be an array of strings`)\n    result.push(value)\n  }\n  return result\n}\n\nfunction sanitizeStringMap(map: Record<string, any>, property: string): Record<string, string> {\n  const result: Record<string, string> = Object.create(null)\n  for (const key in map) {\n    const value = map[key]\n    if (typeof value !== 'string') throw new Error(`key ${quote(key)} in object ${quote(property)} must be a string`)\n    result[key] = value\n  }\n  return result\n}\n\nfunction convertOutputFiles({ path, contents, hash }: protocol.BuildOutputFile): types.OutputFile {\n  // The text is lazily-generated for performance reasons. If no one asks for\n  // it, then it never needs to be generated.\n  let text: string | null = null\n  return {\n    path,\n    contents,\n    hash,\n    get text() {\n      // People want to be able to set \"contents\" and have esbuild automatically\n      // derive \"text\" for them, so grab the contents off of this object instead\n      // of using our original value.\n      const binary = this.contents","sourceCodeStart":1808,"sourceCodeEnd":1844,"githubUrl":"https://github.com/evanw/esbuild/blob/f6058f8364fe7ab91ca57a83e02577ed74c9cae4/lib/shared/common.ts#L1808-L1844","documentation":"The helper `sanitizeStringMap` (lib/shared/common.ts:1822) validates import-attribute objects (the `with` field) returned by onResolve callbacks or passed to `resolve()`. It iterates keys and throws (lib/shared/common.ts:1826) if any value's `typeof` is not `'string'`. The quoted key and property name identify exactly which entry was wrong.","triggerScenarios":"Returning a `with`/import-attributes object from onResolve where a value is a number, boolean, object, or array instead of a string.","commonSituations":"Passing structured import attributes (e.g. `{ with: { type: { x: 1 } } }`); forwarding a parsed JSON object whose values aren't strings; using boolean attributes.","solutions":["Ensure every value in the `with` object is a string, e.g. `{ with: { type: 'json' } }`.","Coerce values with `String(v)` before returning if they are scalar."],"exampleFix":"// before\nreturn { path, with: { type: 1 } };\n// after\nreturn { path, with: { type: 'json' } };","handlingStrategy":"validation","validationCode":"function cleanStringMap(m: Record<string, any>): Record<string, string> {\n  const out: Record<string,string> = {};\n  for (const k in m) { if (typeof m[k] !== 'string') throw new Error(`value for ${k} must be string`); out[k] = m[k]; }\n  return out;\n}","typeGuard":"function isStringMap(m: any): m is Record<string, string> {\n  return typeof m === 'object' && m !== null && Object.values(m).every(v => typeof v === 'string');\n}","tryCatchPattern":null,"preventionTips":["Keep import-attribute values as strings only.","Coerce scalars with String(v) before assignment."],"tags":["plugins","validation","import-attributes","data-shape"],"backgroundTag":null,"analyzedSha":"f6058f8364fe7ab91ca57a83e02577ed74c9cae4","analyzedAt":"2026-08-09T18:37:22.223Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}