diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index 8ca0abf5525763..c7a03d3743f345 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -981,6 +981,11 @@ Removed
be used instead.
(Contributed by Serhiy Storchaka in :gh:`86493`.)
+* Remove the ``errcode.h`` header file. There was never any public tokenizer C
+ API. The ``errcode.h`` header file was only designed to be used by Python
+ internals.
+ (Contributed by Victor Stinner in :gh:`107162`.)
+
Pending Removal in Python 3.14
------------------------------
diff --git a/Include/errcode.h b/Include/internal/pycore_errcode.h
similarity index 90%
rename from Include/errcode.h
rename to Include/internal/pycore_errcode.h
index 54ae929bf25870..96ff31f46f6add 100644
--- a/Include/errcode.h
+++ b/Include/internal/pycore_errcode.h
@@ -1,10 +1,3 @@
-#ifndef Py_ERRCODE_H
-#define Py_ERRCODE_H
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-
/* Error codes passed around between file input, tokenizer, parser and
interpreter. This is necessary so we can turn them into Python
exceptions at a higher level. Note that some errors have a
@@ -13,6 +6,16 @@ extern "C" {
the parser only returns E_EOF when it hits EOF immediately, and it
never returns E_OK. */
+#ifndef Py_INTERNAL_ERRCODE_H
+#define Py_INTERNAL_ERRCODE_H
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef Py_BUILD_CORE
+# error "this header requires Py_BUILD_CORE define"
+#endif
+
#define E_OK 10 /* No error */
#define E_EOF 11 /* End Of File */
#define E_INTR 12 /* Interrupted */
@@ -35,4 +38,4 @@ extern "C" {
#ifdef __cplusplus
}
#endif
-#endif /* !Py_ERRCODE_H */
+#endif // !Py_INTERNAL_ERRCODE_H
diff --git a/Makefile.pre.in b/Makefile.pre.in
index 5f1988b0d17213..85ce4203851ba6 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -1625,7 +1625,6 @@ PYTHON_HEADERS= \
$(srcdir)/Include/dictobject.h \
$(srcdir)/Include/dynamic_annotations.h \
$(srcdir)/Include/enumobject.h \
- $(srcdir)/Include/errcode.h \
$(srcdir)/Include/fileobject.h \
$(srcdir)/Include/fileutils.h \
$(srcdir)/Include/floatobject.h \
@@ -1750,10 +1749,11 @@ PYTHON_HEADERS= \
$(srcdir)/Include/internal/pycore_complexobject.h \
$(srcdir)/Include/internal/pycore_condvar.h \
$(srcdir)/Include/internal/pycore_context.h \
+ $(srcdir)/Include/internal/pycore_descrobject.h \
$(srcdir)/Include/internal/pycore_dict.h \
$(srcdir)/Include/internal/pycore_dict_state.h \
- $(srcdir)/Include/internal/pycore_descrobject.h \
$(srcdir)/Include/internal/pycore_dtoa.h \
+ $(srcdir)/Include/internal/pycore_errcode.h \
$(srcdir)/Include/internal/pycore_exceptions.h \
$(srcdir)/Include/internal/pycore_faulthandler.h \
$(srcdir)/Include/internal/pycore_fileutils.h \
diff --git a/Misc/NEWS.d/next/C API/2023-07-24-00-35-20.gh-issue-107162.7YCEp7.rst b/Misc/NEWS.d/next/C API/2023-07-24-00-35-20.gh-issue-107162.7YCEp7.rst
new file mode 100644
index 00000000000000..cb03cfb1743260
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2023-07-24-00-35-20.gh-issue-107162.7YCEp7.rst
@@ -0,0 +1,3 @@
+Remove the ``errcode.h`` header file. There was never any public tokenizer C
+API. The ``errcode.h`` header file was only designed to be used by Python
+internals. Patch by Victor Stinner.
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 5ccc8958330650..ae518d0bbb709d 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -188,7 +188,6 @@
-
@@ -218,6 +217,7 @@
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 54a77f81a9a1ab..e74bc00ca1e51e 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -81,9 +81,6 @@
Include
-
- Include
-
Include
@@ -558,6 +555,9 @@
Include\internal
+
+ Include\internal
+
Include\internal
diff --git a/Parser/pegen.c b/Parser/pegen.c
index 885d423fca66a9..3f1809707c034f 100644
--- a/Parser/pegen.c
+++ b/Parser/pegen.c
@@ -1,7 +1,7 @@
#include
#include "pycore_ast.h" // _PyAST_Validate(),
+#include "pycore_errcode.h" // E_BADSINGLE
#include "pycore_pystate.h" // _PyThreadState_GET()
-#include
#include "tokenizer.h"
#include "pegen.h"
diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c
index e543d40ccd8ab7..46851602bc30d9 100644
--- a/Parser/pegen_errors.c
+++ b/Parser/pegen_errors.c
@@ -1,6 +1,5 @@
#include
-#include
-
+#include "pycore_errcode.h" // E_TOKEN
#include "pycore_pyerrors.h" // _PyErr_ProgramDecodedTextObject()
#include "tokenizer.h"
#include "pegen.h"
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index ccff16045233de..b84b3fbb0f3cc3 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -3,12 +3,12 @@
#include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgs()
+#include "pycore_errcode.h" // E_OK
#include
#include
#include "tokenizer.h"
-#include "errcode.h"
/* Alternate tab spacing */
#define ALTTABSIZE 1
diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c
index 1938562706914c..cc110b904132df 100644
--- a/Python/Python-tokenize.c
+++ b/Python/Python-tokenize.c
@@ -1,5 +1,5 @@
#include "Python.h"
-#include "errcode.h"
+#include "pycore_errcode.h" // E_TOKEN
#include "../Parser/tokenizer.h"
#include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset()
#include "../Parser/pegen.h" // _PyPegen_byte_offset_to_character_offset()
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index 721c527745c44a..e8e1a2b8f49d4a 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -11,10 +11,10 @@
#include
#include "Python.h"
-
#include "pycore_ast.h" // PyAST_mod2obj
#include "pycore_ceval.h" // _Py_EnterRecursiveCall
#include "pycore_compile.h" // _PyAST_Compile()
+#include "pycore_errcode.h" // E_EOF
#include "pycore_interp.h" // PyInterpreterState.importlib
#include "pycore_object.h" // _PyDebug_PrintTotalRefs()
#include "pycore_parser.h" // _PyParser_ASTFromString()
@@ -24,7 +24,6 @@
#include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_traceback.h" // _PyTraceBack_Print_Indented()
-#include "errcode.h" // E_EOF
#include "marshal.h" // PyMarshal_ReadLongFromFile()
#ifdef MS_WINDOWS