lovell/sharp · error · Error
Expected a valid string to create an image with text.
Error message
Expected a valid string to create an image with text.
What it means
Thrown when inputOptions.text is provided but text.text is not a string (or text itself is not an object with a string text field). The text renderer needs the actual string content to rasterize, so missing/non-string content cannot proceed. This is the else branch after `is.object(text) && is.string(text.text)`.
Source
Thrown at lib/input.mjs:470
}
}
if (is.defined(inputOptions.text.spacing)) {
if (is.integer(inputOptions.text.spacing) && is.inRange(inputOptions.text.spacing, -1000000, 1000000)) {
inputDescriptor.textSpacing = inputOptions.text.spacing;
} else {
throw is.invalidParameterError('text.spacing', 'integer between -1000000 and 1000000', inputOptions.text.spacing);
}
}
if (is.defined(inputOptions.text.wrap)) {
if (is.string(inputOptions.text.wrap) && is.inArray(inputOptions.text.wrap, ['word', 'char', 'word-char', 'none'])) {
inputDescriptor.textWrap = inputOptions.text.wrap;
} else {
throw is.invalidParameterError('text.wrap', 'one of: word, char, word-char, none', inputOptions.text.wrap);
}
}
delete inputDescriptor.buffer;
} else {
throw new Error('Expected a valid string to create an image with text.');
}
}
// Join images together
if (is.defined(inputOptions.join)) {
if (is.defined(this.options.join)) {
if (is.defined(inputOptions.join.animated)) {
if (is.bool(inputOptions.join.animated)) {
inputDescriptor.joinAnimated = inputOptions.join.animated;
} else {
throw is.invalidParameterError('join.animated', 'boolean', inputOptions.join.animated);
}
}
if (is.defined(inputOptions.join.across)) {
if (is.integer(inputOptions.join.across) && is.inRange(inputOptions.join.across, 1, 1000000)) {
inputDescriptor.joinAcross = inputOptions.join.across;
} else {
throw is.invalidParameterError('join.across', 'integer between 1 and 100000', inputOptions.join.across);
}View on GitHub (pinned to 56676c6918)
Solutions
- Wrap the string: sharp({ text: { text: 'hello' } }).
- Coerce non-strings: text: { text: String(value) }.
- Guard that the content is a non-empty string before calling sharp.
Example fix
// before
sharp({ text: 'hello' })
// after
sharp({ text: { text: 'hello' } }) Defensive patterns
Strategy: type-guard
Validate before calling
function textCreate(content, opts = {}) {
if (typeof content !== 'string') {
throw new Error('text.text must be a non-empty string');
}
return sharp({ text: { text: content, ...opts } });
} Type guard
function isTextSpec(text) {
return text !== null && typeof text === 'object' && typeof text.text === 'string';
} Prevention
- Wrap text content at { text: '...' } not at the top level.
- Coerce non-strings with String() before assigning to text.text.
- Validate the content is a non-empty string for meaningful output.
When it happens
Trigger: sharp({ text: { text: 123 } }), sharp({ text: { text: null } }), sharp({ text: {} }) with no text field, or sharp({ text: 'hello' }) passing the string directly instead of wrapping it.
Common situations: Passing the string at the wrong level (sharp({ text: 'hello' }) instead of sharp({ text: { text: 'hello' } })). Forgetting to set the content when building the object programmatically. Receiving text from a non-string source (number id, object) without coercion.
Related errors
- Unsupported input '${input}' of type ${typeof input}${is.def
- Expected noise to be an object
- Expected only one of dpi or height
- Invalid input options ${inputOptions}
- Invalid input
AI-assisted analysis of lovell/sharp@56676c6918 (2026-08-13).
Data as JSON: /api/errors/80efa9651656c929.
Report an issue: GitHub.