evanw/esbuild · error · Error

must be an array of strings

Error message

${quote(property)} must be an array of strings

What it means

The helper `sanitizeStringArray` (lib/shared/common.ts:1813) is used to validate `watchFiles` and `watchDirs` returned by onResolve/onLoad callbacks. It iterates the array and throws (lib/shared/common.ts:1816) for any element whose `typeof` is not `'string'`. The quoted property name tells you which field was malformed.

Solutions

  1. Ensure every element of `watchFiles`/`watchDirs` is a string (e.g. `watchFiles: files.map(f => f.path)`).
  2. Filter out nullish entries before returning: `arr.filter(Boolean)`.

Example fix

// before
return { contents, watchFiles: [{ path: depPath }] };
// after
return { contents, watchFiles: [depPath] };
Defensive patterns

Strategy: validation

Validate before calling

function cleanStringArray(arr: any[]): string[] {
  return arr.map((v, i) => { if (typeof v !== 'string') throw new Error(`element ${i} is not a string`); return v; });
}

Type guard

function isStringArray(a: any): a is string[] {
  return Array.isArray(a) && a.every(v => typeof v === 'string');
}

Prevention

When it happens

Trigger: Returning `watchFiles` or `watchDirs` from an onResolve/onLoad callback where at least one entry is a number, object, null, or undefined instead of a string.

Common situations: Pushing a path object (e.g. `{ path }`) instead of the string path; mixing in `undefined` from an optional field; returning file descriptors instead of paths.

Related errors


AI-assisted analysis of evanw/esbuild@f6058f8364 (2026-08-09). Data as JSON: /api/errors/f0d60f2a0f1912a4. Report an issue: GitHub.

Appendix: source

Thrown at lib/shared/common.ts:1816

    messagesClone.push({
      id: id || '',
      pluginName: pluginName || fallbackPluginName,
      text: text || '',
      location: sanitizeLocation(location, where, terminalWidth),
      notes: notesClone,
      detail: stash ? stash.store(detail) : -1,
    })
    index++
  }

  return messagesClone
}

function sanitizeStringArray(values: any[], property: string): string[] {
  const result: string[] = []
  for (const value of values) {
    if (typeof value !== 'string') throw new Error(`${quote(property)} must be an array of strings`)
    result.push(value)
  }
  return result
}

function sanitizeStringMap(map: Record<string, any>, property: string): Record<string, string> {
  const result: Record<string, string> = Object.create(null)
  for (const key in map) {
    const value = map[key]
    if (typeof value !== 'string') throw new Error(`key ${quote(key)} in object ${quote(property)} must be a string`)
    result[key] = value
  }
  return result
}

function convertOutputFiles({ path, contents, hash }: protocol.BuildOutputFile): types.OutputFile {
  // The text is lazily-generated for performance reasons. If no one asks for
  // it, then it never needs to be generated.

View on GitHub (pinned to f6058f8364)