grafana/k6 · error
couldn't open protoset: %w
Error message
couldn't open protoset: %w
What it means
grpc.Client.load() (init context only) resolves the protoset path against the script's directory and opens it from the init filesystem (initEnv.FileSystems['file']); an Open failure is wrapped as 'couldn't open protoset' (internal/js/modules/k6/grpc/client.go:107). This is purely a file-location problem - distinct from read or unmarshal failures on the same call.
Source
Thrown at internal/js/modules/k6/grpc/client.go:107
return c.convertToMethodInfo(fdset)
}
// LoadProtoset will parse the given protoset file (serialized FileDescriptorSet) and make the file
// descriptors available to request.
func (c *Client) LoadProtoset(protosetPath string) ([]MethodInfo, error) {
if c.vu.State() != nil {
return nil, errors.New("load must be called in the init context")
}
initEnv := c.vu.InitEnv()
if initEnv == nil {
return nil, errors.New("missing init environment")
}
absFilePath := initEnv.GetAbsFilePath(protosetPath)
fdsetFile, err := initEnv.FileSystems["file"].Open(absFilePath)
if err != nil {
return nil, fmt.Errorf("couldn't open protoset: %w", err)
}
defer func() { _ = fdsetFile.Close() }()
fdsetBytes, err := io.ReadAll(fdsetFile)
if err != nil {
return nil, fmt.Errorf("couldn't read protoset: %w", err)
}
fdset := &descriptorpb.FileDescriptorSet{}
if err = proto.Unmarshal(fdsetBytes, fdset); err != nil {
return nil, fmt.Errorf("couldn't unmarshal protoset file %s: %w", protosetPath, err)
}
return c.convertToMethodInfo(fdset)
}
// Note: this function was lifted from `lib/options.go`
func decryptPrivateKey(key, password []byte) ([]byte, error) {View on GitHub (pinned to 93accf6570)
Solutions
- Verify the path relative to the script file (not the CWD) and its exact case
- Ensure the protoset is deployed with the script (COPY in Docker, included when archiving)
- Drop the protoset and use server reflection instead: client.connect(addr, { reflect: true })
Example fix
// before
const methods = grpcClient.load('../pb/service.protoset'); // wrong directory
// after
const methods = grpcClient.load('./pb/service.protoset');
// or skip the file entirely:
// grpcClient.connect(addr, { reflect: true }) Defensive patterns
Strategy: validation
Validate before calling
// fail fast with a clearer error before load()
try {
open('./pb/service.protoset'); // sync builtin open(); throws if the file is missing
} catch (e) {
throw new Error(`protoset missing next to the script: ${e.message}`);
}
const methods = client.load('./pb/service.protoset'); Try / catch
try {
client.load('./pb/service.protoset');
} catch (e) {
if (/couldn't open protoset/.test(e.message)) { /* fix path or fall back to reflect: true */ }
throw e;
} Prevention
- Keep protosets next to the script and reference them relatively
- COPY protosets explicitly in Dockerfiles and CI artifacts
- Prefer reflect: true when the file logistics are fragile
When it happens
Trigger: client.load('./service.protoset') where the file does not exist at the resolved path: typo, wrong case, file in another directory, or the protoset not shipped alongside the script (k6 archive, Docker image, CI checkout).
Common situations: Running k6 from a different working directory; CI jobs copying the script but not sibling files; Docker images missing the ADD/COPY for the protoset; case-sensitive filesystems exposing path-case mistakes.
Related errors
- couldn't read protoset: %w
- couldn't unmarshal protoset file %s: %w
- gRPC exporter endpoint is required
- failed to append ca certificate [%d] from PEM
- failed to append certificate from PEM: %w
AI-assisted analysis of grafana/k6@93accf6570 (2026-08-15).
Data as JSON: /api/errors/88c4f218d0290791.
Report an issue: GitHub.