Visitar URL original
A type rename renames every TypeIndex but never re-keys the schema's index map, so the index answers to a name nothing resolves: DROP and REBUILD INDEX fail, CREATE INDEX on a new type of the old name is refused, and a manual index name is lost · Issue #10751 · ArcadeData/arcadedb · GitHub
Skip to content

A type rename renames every TypeIndex but never re-keys the schema's index map, so the index answers to a name nothing resolves: DROP and REBUILD INDEX fail, CREATE INDEX on a new type of the old name is refused, and a manual index name is lost #10751

Closed

Description

@ruispereira

SEVERITY: HIGH

Summary

TypeIndex.updateTypeName recomputes the wrapper's logicName from the type's new name, and
nothing re-keys LocalSchema.indexMap. From that moment the index reports Bar[a] while the only
key that reaches it is Foo[a]. Five consequences, all reproduced:

  1. DROP INDEX "Bar[a]" and REBUILD INDEX "Bar[a]" fail with "Index not found", using the exact
    name SELECT FROM schema:indexes prints.
  2. DROP INDEX "Foo[a]" succeeds, dropping the index of a type that no longer exists under that
    name.
  3. Creating a new type under the freed name Foo and indexing the same property is refused with
    "Index 'Foo[a]' already exists", because the stale key is still occupied by the other type's
    index.
  4. DROP TYPE Bar leaves the wrapper in indexMap (its cleanup looks it up by getName()), and
    SELECT FROM schema:indexes then throws SchemaException: Type with name 'Bar' was not found
    for every caller until the database is reopened.
  5. A manual index name is lost permanently. typeIndexFor honours metadata.typeIndexName when it
    mints a wrapper (issue Manual index name is ignored when create an index #4139), but updateTypeName overwrites logicName unconditionally, and
    toJSON persists a manual name only when i.getName() differs from the auto-derived form, which
    it no longer does. After the rename and one reopen the user-chosen name is gone from
    schema.json.

LocalSchema.indexRenamed exists precisely to keep this map honest, and its javadoc states the rule
that is broken: "the schema keeps resolving it under IndexInternal#getName() at every moment of
its life" and "Only LSMVectorIndex renames itself ... Every other index type keeps its creation
name for life, which is why this had no counterpart before." TypeIndex renames itself on every
type rename and never calls it.

Where (HEAD 888b83c)

  • engine/src/main/java/com/arcadedb/index/TypeIndex.java:737 - updateTypeName assigns
    logicName and ignores metadata.typeIndexName.
  • engine/src/main/java/com/arcadedb/schema/LocalDocumentType.java:789 and :799 - the rename
    loops call idx.updateTypeName(...) / idx.updateTypeNameOfSubIndexesOn(...) and never call
    schema.indexRenamed(...); neither does the rollback at :833.
  • engine/src/main/java/com/arcadedb/schema/LocalSchema.java:5492 - indexRenamed, whose only
    caller is engine/src/main/java/com/arcadedb/index/vector/LSMVectorIndex.java:886.
  • engine/src/main/java/com/arcadedb/schema/LocalDocumentType.java:2425 - typeIndexFor honours a
    manual name when minting.
  • engine/src/main/java/com/arcadedb/schema/LocalDocumentType.java:2974 - toJSON decides a name is
    "custom" by comparing it with the auto-derived form.

Repro

Probe ProbeB, default-named index:

CREATE DOCUMENT TYPE Foo
CREATE PROPERTY Foo.a STRING
CREATE INDEX ON Foo (a) UNIQUE
ALTER TYPE Foo NAME Bar

after rename: names = Bar[a] Foo_0_4064685322655750
after rename: exists(Bar[a])=false exists(Foo[a])=true
DROP INDEX `Bar[a]` -> CommandExecutionException: Index not found: Bar[a]
REBUILD INDEX `Bar[a]` -> IndexException: Error on rebuilding index 'Bar[a]' (error=Index with name 'Bar[a]' was not found)
DROP INDEX `Foo[a]` (the type Foo no longer exists) -> OK, dropped
end: names =

Probe ProbeG, the same rename followed by recreating a type under the freed name and then dropping
the renamed one:

after rename: names = Bar[a] Foo_0_4065059139257583
CREATE INDEX ON the new Foo (a) -> AlreadyExistsException: Index 'Foo[a]' already exists
after re-creating Foo: names = Bar[a] Foo_0_4065059139257583
exists(Bar[a]) = false
DROP TYPE Bar -> OK
end: names = Bar[a] | existsType(Bar)=false
schema:indexes -> SchemaException: Type with name 'Bar' was not found
after reopen: names =

Probe ProbeA, manual index name, across a close and reopen:

CREATE INDEX MyIdx ON Foo (a) UNIQUE
ALTER TYPE Foo NAME Bar

after create: exists(MyIdx)=true
after create: index names = MyIdx Foo_0_4064593401166791
after rename: exists(MyIdx)=true
after rename: exists(Bar[a])=false
after rename: index names = Bar[a] Foo_0_4064593401166791
after rename: getIndexByName(MyIdx).getName() = Bar[a]
after reopen: exists(MyIdx)=false
after reopen: exists(Bar[a])=true
after reopen: index names = Foo_0_4064593401166791 Bar[a]

Refutation attempted

  • Is the map rebuilt soon enough for this to be invisible? No. It is rebuilt only by a schema
    load. The probes above run entirely in one session after the rename, and the ProbeG catalog
    failure persists until the reopen on the last line.
  • Is schema.json wrong too? No, and that is worth stating: saveConfiguration serialises
    indexes from getAllIndexes(), not from indexMap, so the file is consistent and a reopen heals
    consequences 1 to 4. Consequence 5 is the one the reopen makes permanent, because the manual name
    is not written at all.
  • Does the bucket-level index have the same problem? No. LSMTreeIndex.updateTypeName
    (engine/src/main/java/com/arcadedb/index/lsm/LSMTreeIndex.java:299) moves the file and updates
    metadata.typeName but leaves name alone, so its indexMap key stays correct. Only the
    TypeIndex wrapper changes the name it answers to.
  • Does the transaction-index-lane problem of LSM_VECTOR: writes right after COMPACT INDEX (same session) are silently not indexed #6105 reappear? I could not make it: the lanes are
    keyed by the BUCKET-level index name, which does not change. Not reproduced, and I am not claiming
    it.
  • Is the manual-name loss perhaps intended, a manual name being type-scoped? Nothing says so, and
    the opposite is documented: typeIndexFor calls the manual name "the name a user's SELECT
    resolves", and IndexBuilder.conflictWithExistingIndexName says "an index is reachable only
    through its name", listing DROP INDEX <name> and REBUILD INDEX <name>.

Suggested fix

In LocalDocumentType.renameInternal, capture each TypeIndex's name before updateTypeName and
call schema.indexRenamed(oldLogicName, idx) after it, and do the same in reverse in the rollback
loops. In TypeIndex.updateTypeName, leave the name alone when the wrapper carries a manual name,
which is the same condition typeIndexFor already evaluates when it mints one.

THE GUARANTEE. Nothing should be able to change what IndexInternal.getName() answers without the
schema's map following in the same step. Make logicName unassignable from outside and give LocalSchema the single entry point (renameIndex(index, newName)) that assigns it, re-keys indexMap and notifies the transaction manager, so there is no way to do half of it. The census
test must enumerate the IndexInternal implementations from the index factory's registered handlers
rather than from a list in the test, call the rename hook on each, and assert schema.getIndexByName(index.getName()) == index and existsIndex(oldName) == false afterwards; a
second case must rename a type carrying a manually named index, reopen, and assert the manual name
still resolves. A weaker assertion passes today: checking only that index.getName() changed, or
that schema.json round-trips, both succeed while every consequence above remains.

Scope / confidence

Executed: ProbeA, ProbeB, ProbeG, outputs verbatim above. Read, not executed: the rollback
path (LocalDocumentType.java:833) needing the inverse call, and the claim that indexRenamed's TransactionManager notification is also skipped.

Dedup

Checked alltitles.txt for rename (#10412, #10317, #10096, #9891, #9762, #9434), for DROP INDEX/REBUILD INDEX/index name (#10734, #10589, #9848, #9812, #9811, #9705, #9651, #9615,
#9254, #9213, #9071) and for schema:indexes (none). #10412 is the nearest neighbour, "DROP TYPE
and ALTER TYPE ... BUCKET fail after an indexed supertype rename", and it is about a SUPERTYPE
rename unlinking sub-index bindings; the defect here is the schema's name-to-index map not following
a rename at all, which bites with no inheritance in the picture. #9213 is about the LSM bucket-index
file name diverging between leader and followers after a compaction, a different map and a different
cause. #9434 is a manual LSM index renamed by a compaction, again the bucket-level component.


Census and refuted leads

Activity

  1. added
    engineCore engine: document/schema API
    severity:majorA feature is broken or returns wrong results, with no practical workaround
    on Oct 26, 2026
  2. added this to the 26.11.1 milestone on Oct 26, 2026
  3. added
    in progressThe team is actively working on this issue
    on Oct 27, 2026
  4. self-assigned this
    on Oct 27, 2026
  5. added a commit that references this issue on Oct 27, 2026
  6. lvca commented on Oct 27, 2026

    @lvca
    Member

    Fixed in #10816 (26.11.1).

    After ALTER TYPE Foo NAME Bar, the index Foo[a] is now Bar[a] everywhere straight away: DROP INDEX, REBUILD INDEX and schema:indexes all find it by its new name, and the old name no longer reaches it. A new type can be created under the freed name and indexed again, and dropping the renamed type leaves nothing behind.

    An index you named yourself (CREATE INDEX MyIdx ON Foo (a)) keeps that name through the rename and after a restart.

    A rename is refused, with nothing changed, if one of the type's indexes would take a name another index already has.


    ❤️ Thanks for helping make ArcadeDB better! ArcadeDB is free and open source, sustained by its community. If it's useful to you or your company, please consider becoming a sponsor to keep development going.

  7. removed
    in progressThe team is actively working on this issue
    on Oct 27, 2026
  8. ruispereira commented on Oct 28, 2026

    @ruispereira
    ContributorAuthor

    Re-validated at main 0d9d8ce. COMPLETE: all five consequences re-run and all five gone, including the manual index name surviving a rename and a reopen. The guard is at the authority: logicName is private volatile, assigned only by a private rename() that calls schema.indexRenamed in the same step and rolls the name back if the map refuses, and indexRenamed itself now refuses to take another index's name. Hierarchy cases the shipped test omits (supertype rename with an inherited index, subtype rename, a manual name on a supertype index) were also run; every listed index still resolves to itself after each, and after a reopen.

    One residual, reproduced. A hand-spelled name that happens to equal the derived form is still lost to a rename:

    CREATE INDEX `Foo[a]` ON Foo (a) UNIQUE
    ALTER TYPE Foo NAME Bar
    -> the index is now Bar[a]; the user's chosen name is gone
    

    This is deliberate per the comment at LocalDocumentType:2498: REBUILD hands the derived name back as the custom one, so the two are indistinguishable after the fact. The shape that would close it is recording manual-ness where the name is SUPPLIED, a flag on IndexBuilder set by CREATE INDEX when it carried a name, instead of deriving it by comparing two strings.

    Two sub-tests of the new class (aRenameBackRestoresTheOriginalNames, aRefusedRenameLeavesTheIndexUnderItsOldName) pass with the production change reverted. Five of seven carry the issue, so the class is not inert, but those two are regression guards rather than defect pins.

    One correction to our own report: in consequence 5 we gave the mechanism backwards. updateTypeName overwrites the name first, and the toJSON comparison is only what makes the loss permanent. Both had to change, and both did.

  9. added a commit that references this issue on Nov 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugengineCore engine: document/schema APIseverity:majorA feature is broken or returns wrong results, with no practical workaroundsql

Type

No type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions