Skip to content

Conversation

mstoykov
Copy link
Contributor

What?

This doesn't abort immediately the execution, but continues the resolution step and then errors if there are any unknown modules.

Why?

This allows the resolution to continue finding unknown modules and potentially even let us then get a new binary that can run the script.

Checklist

  • I have performed a self-review of my code.
  • I have commented on my code, particularly in hard-to-understand areas.
  • I have added tests for my changes.
  • I have run linter and tests locally (make check) and all pass.

Checklist: Documentation (only for k6 maintainers and if relevant)

Please do not merge this PR until the following items are filled out.

  • I have added the correct milestone and labels to the PR.
  • I have updated the release notes: link
  • I have updated or added an issue to the k6-documentation: grafana/k6-docs#NUMBER if applicable
  • I have updated or added an issue to the TypeScript definitions: grafana/k6-DefinitelyTyped#NUMBER if applicable

Related PR(s)/Issue(s)

@mstoykov mstoykov added this to the v1.4.0 milestone Oct 10, 2025
@mstoykov mstoykov requested a review from a team as a code owner October 10, 2025 15:48
@mstoykov mstoykov requested review from ankur22 and inancgumus and removed request for a team October 10, 2025 15:48
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 10, 2025 15:53 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 10, 2025 15:57 — with GitHub Actions Inactive
inancgumus
inancgumus previously approved these changes Oct 13, 2025
Comment on lines 354 to 364
return fmt.Sprintf("unknown modules %q were tried to be loaded, but couldn't - "+
"this likely means binary provisioning is required or a custom k6 binary with more extensions",
u.unknownModules)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the wording should be along the lines of:

couldn't load unknown modules %q -- likely due to either requiring binary provisioning or needing a custom k6 binary with the required extensions.

Copy link
Contributor

@codebien codebien Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Sprintf("unknown modules %q were tried to be loaded, but couldn't - "+
"this likely means binary provisioning is required or a custom k6 binary with more extensions",
u.unknownModules)
return fmt.Sprintf("unknown modules %q were tried to be loaded, but couldn't - "+
"this likely means automatic extension extension is required or a custom k6 binary with more extensions",
u.unknownModules)

in addition to @ankur22's suggestion, binary provisioning is an outdated name

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@codebien FYI: automatic extension extension

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've updated the message

ankur22
ankur22 previously approved these changes Oct 13, 2025
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 14, 2025 08:34 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 14, 2025 08:35 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 14, 2025 09:00 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 14, 2025 09:01 — with GitHub Actions Inactive
@mstoykov mstoykov force-pushed the moduleResoverExtraction branch from debf652 to 43b615c Compare October 14, 2025 09:23
@mstoykov mstoykov force-pushed the allUnknownModulesDetection branch from dd68b1a to 1ae83b8 Compare October 14, 2025 09:24
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 14, 2025 09:30 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 14, 2025 09:32 — with GitHub Actions Inactive
Base automatically changed from moduleResoverExtraction to master October 15, 2025 15:26
@mstoykov mstoykov dismissed stale reviews from ankur22 and inancgumus October 15, 2025 15:26

The base branch was changed.

@mstoykov mstoykov force-pushed the allUnknownModulesDetection branch from 1ae83b8 to 4d232bb Compare October 16, 2025 08:10
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 16, 2025 08:16 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 16, 2025 08:18 — with GitHub Actions Inactive
@mstoykov mstoykov requested a review from codebien October 16, 2025 13:14
This doesn't abort immediately the execution, but continues the
resolution step and then errors if there are any unknown modules.

This allows the resolution to continue finding unknown modules and
potentially even let us then get a new binary that can run the script.
@mstoykov mstoykov force-pushed the allUnknownModulesDetection branch from 4d232bb to 2142f1a Compare October 17, 2025 15:37
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 17, 2025 15:44 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 17, 2025 15:46 — with GitHub Actions Inactive
Copy link
Contributor

@codebien codebien left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main logic LGTM, added a few minor comments

panic("somehow running source data for " + specifier + " didn't produce a cyclic module record")
}

unknownModules := mr.unknownModules()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
unknownModules := mr.unknownModules()
if mr.unknownModules() > 0 {
return newUnknownModulesError(mr.unknownModules())
}

We can probably avoid to allocate it for the happy path

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went with two different thigns and in the end remembered that where we add to the map, we already go through cachining so it will be called once. So I opted for just adding to a slice in the end.

Comment on lines 354 to 364
return fmt.Sprintf("unknown modules %q were tried to be loaded, but couldn't - "+
"this likely means binary provisioning is required or a custom k6 binary with more extensions",
u.unknownModules)
Copy link
Contributor

@codebien codebien Oct 17, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return fmt.Sprintf("unknown modules %q were tried to be loaded, but couldn't - "+
"this likely means binary provisioning is required or a custom k6 binary with more extensions",
u.unknownModules)
return fmt.Sprintf("unknown modules %q were tried to be loaded, but couldn't - "+
"this likely means automatic extension extension is required or a custom k6 binary with more extensions",
u.unknownModules)

in addition to @ankur22's suggestion, binary provisioning is an outdated name

@mstoykov mstoykov requested a review from codebien October 20, 2025 08:44
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 20, 2025 08:50 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 20, 2025 08:52 — with GitHub Actions Inactive
@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 21, 2025 08:54 — with GitHub Actions Inactive
}

func (u UnknownModulesError) Error() string {
return fmt.Sprintf("unknown modules [%s] were tried to be loaded, but couldn't - "+
Copy link
Contributor

@codebien codebien Oct 21, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there is still a bit of improvement to be done to have a better DX. A revisited version of original Ankur's proposal.

Suggested change
return fmt.Sprintf("unknown modules [%s] were tried to be loaded, but couldn't - "+
return fmt.Sprintf("unknown module(s): [%s] k6 couldn't resolve the them because they are not built-in k6 modules. If these are extension modules, enable automatic extension resolution or build a custom binary with xk6. See the docs for more details: https://grafana.com/docs/k6/latest/extensions/explore/#use-extensions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that we are going overboard on this.

There are more changes to come, and this error is either never going to be seen. Or it will be seen before it either loads a new binary or returns a next error about extension resolutions.

I would prefer all the DX/UX work to be done after we move to the new implementation, which already fix bugs that are reported and people have problems with. I do not think that if someone has disabled auto extension resolution, they would not know about extensions.

@mstoykov mstoykov temporarily deployed to azure-trusted-signing October 21, 2025 09:06 — with GitHub Actions Inactive
}
}

// UnknownModulesError is returned when loading a module was not possbile due to one or more of dependencies
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// UnknownModulesError is returned when loading a module was not possbile due to one or more of dependencies
// UnknownModulesError is returned when loading a module was not possible due to one or more of dependencies

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit; ofc non-blocking.

Copy link
Contributor

@joanlopez joanlopez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't fully understand the role of the unknownModule and whether panicicking only on Evaluate is enough to catch any possible misuse, but overall looks good 👍🏻

@mstoykov
Copy link
Contributor Author

@joanlopez if the loading could find a module, the Sobek (ESM) resolution mechanism will stop ... because well, it could find it. But what we want here is for it to continue until we have loaded everything that we can. And then we will check "did we try to load anything that was not found" if so ... abort and propagate back what that was.

This allows us to have k6 internally figure out that k6/x/sql and k6/x/faker are not found, but we need them for the script. Instead of it stopping on the first one.

The panic is because an unknown module should never actually be evaluated, if it is that is a bug somewhere else. We only parse the code and link the modules together.

@mstoykov mstoykov merged commit 3c2911f into master Oct 21, 2025
40 of 41 checks passed
@mstoykov mstoykov deleted the allUnknownModulesDetection branch October 21, 2025 14:17
@joanlopez
Copy link
Contributor

@mstoykov Thanks for the detailed explanation! 🙌🏻 🙇🏻

I think I got most of it (especially the high-level picture, and the main purpose), what I wasn't completely sure was if there could be a misuse (now or introduced in the future by mistake) somehow hidden because only Evaluate panics. But I guess it's fine for now. Again, thanks! 👍🏻

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants