[vim/vim] E1041 is thrown when a variable is exported from a script contained in the autoload/ folder and the script is sourced more than once (Issue #19205)

24 views
Skip to first unread message

ubaldot

unread,
Jan 17, 2026, 11:31:07 PMJan 17
to vim/vim, Subscribed
ubaldot created an issue (vim/vim#19205)

Steps to reproduce

Create ~/vimfiles/autoload/x.vim with the following content:

vim9script

export enum Fruit
  Banana,
  Apple
endenum

If you source it twice, then you get E1041.

If you move away the script from autoload folders, then you can source it as many way as you want.

Expected behaviour

It should be possible to source the script as many times as user want without throwing any error.

Version of Vim

9.1-1942

Environment

Win 11

Logs and stack traces


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205@github.com>

h_east

unread,
Feb 3, 2026, 8:34:58 AMFeb 3
to vim/vim, Subscribed
h-east left a comment (vim/vim#19205)

This seems working as expected.
Files under autoload/ update the loaded information for the file path name (x in this case) the first time they are loaded.
The first time :so is used, the loaded information for the file path name (x) is internally updated to indicate that it has been loaded, but the second time :so is used, the file has already been loaded, resulting in an E1041 error.

Normally, Vim9 scripts use import autoload for the autoload mechanism.
This allows control that loads only the first time to work correctly.

vim9script

import autoload 'x.vim'

var f = x#Fruit.Banana
echo $"f: {f.name}"


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/3841359203@github.com>

h_east

unread,
Feb 3, 2026, 9:55:41 AMFeb 3
to vim/vim, Subscribed
h-east left a comment (vim/vim#19205)

@yegappan What is your take on this?


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/3841820954@github.com>

ubaldot

unread,
Feb 3, 2026, 1:01:06 PMFeb 3
to vim/vim, Subscribed
ubaldot left a comment (vim/vim#19205)

So what is the point of having noclear and why moving scripts in another folder won't suffer the same problem. The current behavior is cumbersome in vim9 context.

I could understand such a behavior in legacy-vim (and for every script), but definitely not in Vin9.
In vim9 you have noclear if you really want such a behavior.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/3842679884@github.com>

h_east

unread,
Feb 4, 2026, 12:20:38 AMFeb 4
to vim/vim, Subscribed
h-east left a comment (vim/vim#19205)

Normal def functions can be redefined, but since enum/class are part of the type system, I believe redefining them is prohibited due to compatibility issues with existing instances.

I think you should either use import autoload, or define export enum and export class outside of autoload/.

If you are developing a plugin and have made changes to autoload/x.vim, restart Vim.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/3845396662@github.com>

h_east

unread,
Feb 4, 2026, 4:01:15 AMFeb 4
to vim/vim, Subscribed
h-east left a comment (vim/vim#19205)

https://github.com/vim/vim/blob/4b83d5ca76573373c0b57238b221a6a504bdb50b/runtime/doc/vim9.txt#L396-L397

Document says:

Reloading a Vim9 script clears functions and variables by default

In other words, nothing other than functions and variables will be cleared.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/3846178732@github.com>

Mao-Yining

unread,
Jul 2, 2026, 7:51:35 AMJul 2
to vim/vim, Subscribed
mao-yining left a comment (vim/vim#19205)

@yegappan Is this the final decision? I don't think 'autoload' dir is very special. If you suggest to develop vimclass or enum in different directory, could you please point it out in the document?


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/4865362152@github.com>

Mao-Yining

unread,
Jul 5, 2026, 12:33:43 AMJul 5
to vim/vim, Subscribed
mao-yining left a comment (vim/vim#19205)

@h-east

In other words, nothing other than functions and variables will be cleared.

In fact, only functions can now be cleard for files under autoload/. Variables still have this problem for both var and const.

vim9script

export def F()
enddef

export var a = ''


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/4884837983@github.com>

h_east

unread,
Jul 6, 2026, 7:25:26 AMJul 6
to vim/vim, Subscribed
h-east left a comment (vim/vim#19205)

Thanks for the follow-up. There are two separate cases here.

Exported var/const (and functions)

An exported item of an autoload script lives in the global namespace with the
autoload prefix (e.g. x#a). On reload the script-local items are cleared but
these globals were not, so a second :source of an exported var/const hit
the redefine guard (E1041). Functions were already replaced on reload; that is
the asymmetry you noted.

The PR gives exported var/const the same clean slate as functions, so an
autoload script can be sourced more than once. The new definition wins (value
and type), and a genuine duplicate within one script still errors.

Exported enum/class

These stay E1041. A reloaded class or enum cannot update objects created from
the old definition (they keep it via reference counting), so only new instances
would see the change. Forcing a restart is more honest than a half-applied
reload.

This is a behaviour choice, not a safety limit: allowing it does not crash or
corrupt memory (member access is checked against each object's own class).
Whether to relax it for an unchanged reload is a design question better settled
with the class/enum owners, so the PR keeps the current behaviour.

Usage

The supported way to use an autoload script is import autoload, which loads it
once and never hits this. For a changed class or enum, restarting Vim remains
the reliable approach.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/4892216875@github.com>

ubaldot

unread,
Jul 21, 2026, 5:11:27 AM (3 days ago) Jul 21
to vim/vim, Subscribed
ubaldot left a comment (vim/vim#19205)

@chrisbra as the accepted solution of this issue is cf80f13, then at bare minimum the documentation of autoload shall be updated with something like the following:

... when a script is in autoload/ folder and noclear is not specified in the script, then sourcing such script leaves vim in a hybrid state where variables, constants and functions are cleared but enum and classes retain the previous state. To clean enum and classes you must close and re-open vim.

However, sourcing a script located in any other folder than autoload/ has the following effect:

  • If noclear is specified, then variables, constants, functions classes and enum retain the previous state,
  • If noclear is not specified, then variables, constants, functions classes and enum are cleared,

thus leaving Vim in a consistency state. There is no need to close and re-open vim.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/5032164659@github.com>

Christian Brabandt

unread,
Jul 22, 2026, 5:19:09 PM (2 days ago) Jul 22
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#19205)

Thanks, I'll update it slightly to mention the autoload folder


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/5051671480@github.com>

ubaldot

unread,
Jul 23, 2026, 5:48:38 PM (13 hours ago) Jul 23
to vim/vim, Subscribed
ubaldot left a comment (vim/vim#19205)

Thanks. I was reflecting why exported class/enums cannot be redefined if located in autoload/ but can be redefined if located in any other folder, e.g. lib/ given that from the docs it is not very clear and such a behavior looks fairly inconsistent.

I may be wrong, but I think the reason may be due to the induced scope when sourcing items from autoload/ and when sourcing from any other place. I try to explain better below.

Say that I have a script my_script.vim that includes the following snippet:

export  enum Color
	White,
	Red,
	Green, Blue, Black
    endenum

If I source autoload/my_script.vim, then the enum Color goes in the global namespace. Hence, once I source again the script, Vim already find it defined in the global namespace and return error.

On the other hand, if I source lib/my_script.vim, then then the enum Color is kept script-local.

Next, if in foo.vim I add the following code:

import autoload  '../lib/my_script'

then enum Color won't become global, despite of the keyword autoload.

In-fact, such an autoload keyword only indicates a lazy loading and should have nothing to do with the autoload keyword used to indicate the autoload/ folder (in-fact, I would have used another keyword e.g. lazyload and use that one e.g. import lazyload '../lib/my_script.vim').
With import autoload '../lib/my_script the enum Color retain its script-local sope!
This is the reason why you can source lib/my_script.vim over and over with no problems: simply because enum Color is not found in the global namespace!

I am not sure if I get it right, @h-east or @chrisbra may confirm, because from the docs it is difficult to deduct it.

If the above explanation is correct, perhaps it should be clarified in the docs, and, less important, I would definitely avoid the autoload/ like the plague for my plugins in the future.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/5063867389@github.com>

h_east

unread,
Jul 23, 2026, 9:02:47 PM (10 hours ago) Jul 23
to vim/vim, Subscribed
h-east left a comment (vim/vim#19205)

Your understanding is correct, including the key point that lazy loading and the
autoload/ folder are two separate things.

To put the mechanism precisely: a script is an "autoload script" purely by its
path. If the path contains /autoload/, Vim derives a prefix dir#script# from
the file name and registers every exported item in the global namespace under
it (e.g. my_script#Color), the same convention as foo#bar() autoload
functions. On a re-source, var/const are cleared and redefined, but classes
and enums are intentionally kept (existing instances still point at the old
definition, so Vim asks for a restart instead of a half-updated state), which is
why you get E1041. A script not under /autoload/ gets no prefix, its items
stay script-local, and re-sourcing works. This depends only on the path, so even
a direct :source autoload/x.vim globalizes.

import autoload is the separate axis: it just means "load lazily," so
import autoload '../lib/x.vim' outside autoload/ is still deferred, not an
eager import. The only nuance to "nothing to do with the autoload folder" is
that a bare name like import autoload 'for/search.vim' does look in the
autoload/ directories of 'runtimepath'; a relative or absolute path detaches
the two completely.

Agreed the docs could make the path-based prefixing and its effect on
re-sourcing clearer.


Reply to this email directly, view it on GitHub, or unsubscribe.
Triage notifications, keep track of coding agent tasks and review pull requests on the go with GitHub Mobile for iOS and Android. Download it today!

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19205/5065053347@github.com>

Reply all
Reply to author
Forward
0 new messages