apple/pkl · error
charIndexOutOfRange
charIndexOutOfRange
Error message
charIndexOutOfRange ${index} 0 ${max} What it means
Indexing a String with `[i]` in Pkl indexes code points; when the index is negative, beyond the last code point, or falls inside a surrogate pair boundary, Pkl throws `charIndexOutOfRange` showing the valid range 0..max. It protects against out-of-bounds character access.
Source
Thrown at pkl-core/src/main/java/org/pkl/core/ast/expression/binary/SubscriptNode.java:43
import com.oracle.truffle.api.source.SourceSection;
import org.jspecify.annotations.Nullable;
import org.pkl.core.runtime.*;
import org.pkl.core.runtime.VmReference.VmReferenceAccessError;
import org.pkl.core.runtime.VmReference.VmReferenceAccessErrorType;
import org.pkl.core.util.ErrorMessages;
@NodeInfo(shortName = "[]")
public abstract class SubscriptNode extends BinaryExpressionNode {
protected SubscriptNode(SourceSection sourceSection) {
super(sourceSection);
}
@Specialization
@TruffleBoundary
protected String eval(String receiver, long index) {
var charIndex = VmUtils.codePointOffsetToCharOffset(receiver, index);
if (charIndex == -1 || charIndex == receiver.length()) {
throw exceptionBuilder()
.evalError(
"charIndexOutOfRange", index, 0, receiver.codePointCount(0, receiver.length()) - 1)
.withSourceSection(getRightNode().getSourceSection())
.withProgramValue("String", receiver)
.build();
}
if (Character.isHighSurrogate(receiver.charAt(charIndex))
&& charIndex < receiver.length() - 1
&& Character.isLowSurrogate(receiver.charAt(charIndex + 1))) {
return receiver.substring(charIndex, charIndex + 2);
}
return receiver.substring(charIndex, charIndex + 1);
}
@Specialization
protected Object eval(VmList receiver, long index) {
if (index < 0 || index >= receiver.getLength()) {View on GitHub (pinned to f3efcbfc9b)
Solutions
- Bounds-check the index against `s.length - 1` (actually codePointCount - 1) before indexing
- Handle the empty-string case separately
- Use `s.substring(...)` or iterate instead of direct indexing when bounds are uncertain
Example fix
// before (Pkl) val c = name[name.length - 1] // after val c = name.isEmpty() ? null : name[name.length - 1]
Defensive patterns
Strategy: validation
Validate before calling
function safeCharAt(s, i) {
if (typeof s !== 'string' || !Number.isInteger(i)) return null;
return (i >= 0 && i < s.length) ? s[i] : null;
} Prevention
- Remember valid range is 0..(codePointCount - 1)
- Handle empty strings before indexing
- Prefer substring/iteration over positional access
When it happens
Trigger: `s[index]` where index < 0 or index >= number of code points, e.g. `"abc"[5]` or `"abc"[-1]`.
Common situations: Off-by-one errors using `length` instead of `length - 1`, parsing possibly-empty strings, or indexing user-supplied offsets.
Related errors
- charIndexOutOfRange
- Cannot convert pkl.base#String `%s` to java.lang.Character b
- elementIndexOutOfRange
- elementIndexOutOfRange
- elementIndexOutOfRange
AI-assisted analysis of apple/pkl@f3efcbfc9b (2026-09-08).
Data as JSON: /api/errors/144644dbc851b817.
Report an issue: GitHub.