{"record":{"id":"0ee4cbfc5cef637c","repo":"siyuan-note/siyuan","slug":"cannot-remove-primary-key-field-attribute-view-fields","errorCode":null,"errorMessage":"cannot remove primary key field","messagePattern":"cannot remove primary key field","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"kernel/model/attribute_view_fields.go","lineNumber":109,"sourceCode":"\t\t\treturn nil, loadErr\n\t\t}\n\t\tcopy, copyErr := cloneAttributeViewForFieldMutation(current)\n\t\tif copyErr != nil {\n\t\t\treturn nil, copyErr\n\t\t}\n\t\tbefore[id], views[id] = copy, current\n\t\treturn current, nil\n\t}\n\tsource, err := load(op.AvID, false)\n\tif err != nil {\n\t\treturn err\n\t}\n\tkey, err := source.GetKey(op.ID)\n\tif err != nil {\n\t\treturn err\n\t}\n\tif key.Type == av.KeyTypeBlock {\n\t\treturn errors.New(\"cannot remove primary key field\")\n\t}\n\tremovals := map[string][]string{source.ID: {key.ID}}\n\tif relation := key.Relation; key.Type == av.KeyTypeRelation && relation != nil && relation.IsTwoWay && relation.AvID != \"\" {\n\t\tdest, loadErr := load(relation.AvID, true)\n\t\tif loadErr != nil {\n\t\t\treturn loadErr\n\t\t}\n\t\tif dest != nil {\n\t\t\tback, _ := dest.GetKey(relation.BackKeyID)\n\t\t\tif back != nil && back.Type == av.KeyTypeRelation && back.Relation != nil &&\n\t\t\t\tback.Relation.AvID == source.ID && back.Relation.IsTwoWay {\n\t\t\t\tif back.Relation.BackKeyID != key.ID {\n\t\t\t\t\treturn fmt.Errorf(\"database back relation field [%s] has changed\", back.ID)\n\t\t\t\t}\n\t\t\t\tif op.RemoveDest {\n\t\t\t\t\tremovals[dest.ID] = append(removals[dest.ID], back.ID)\n\t\t\t\t} else {\n\t\t\t\t\tback.Relation.IsTwoWay, back.Relation.BackKeyID = false, \"\"","sourceCodeStart":91,"sourceCodeEnd":127,"githubUrl":"https://github.com/siyuan-note/siyuan/blob/9f775e8a12daef8255556097396f9b2739078892/kernel/model/attribute_view_fields.go#L91-L127","documentation":"removeAttributeViewField refuses to delete a database (attribute view) field whose type is av.KeyTypeBlock, i.e. the primary key / block-name column. The primary key is the structural anchor that maps rows to real document blocks, so the kernel treats it as permanently non-removable and returns this plain error instead of deleting the field.","triggerScenarios":"Calling removeAttributeViewField (exposed via the removeAttrViewColumn transaction action or RemoveAttributeViewKey API) with op.ID pointing at the field of type KeyTypeBlock in the target attribute view.","commonSituations":"A plugin or script tries to delete 'the first column' of a database programmatically without checking its type; a UI integration passes a column id obtained from a table layout where the block column is listed alongside normal columns; an API consumer misidentifies the row-title column as an ordinary text field.","solutions":["Check key.Type before removing: only issue removeAttrViewColumn for fields whose type is not av.KeyTypeBlock","If the goal is hiding rather than deleting, remove or hide the corresponding view table column (ViewTableColumn) instead of deleting the field definition","If the whole database is unwanted, delete the attribute view itself rather than its primary key field"],"exampleFix":"// before\nops := []*model.Operation{{Action: \"removeAttrViewColumn\", AvID: avID, ID: colID}}\n// after\navObj, _ := model.ParseAttributeView(avID)\nkey, _ := avObj.GetKey(colID)\nif key != nil && key.Type != av.KeyTypeBlock {\n    ops := []*model.Operation{{Action: \"removeAttrViewColumn\", AvID: avID, ID: colID}}\n}","handlingStrategy":"validation","validationCode":"av, err := model.ParseAttributeView(avID)\nif err != nil { return err }\nkey, err := av.GetKey(fieldID)\nif err != nil { return err }\nif key.Type == av.KeyTypeBlock {\n    return fmt.Errorf(\"field %s is the primary key and cannot be removed\", fieldID)\n}","typeGuard":"func isRemovableField(k *av.Key) bool { return k != nil && k.Type != av.KeyTypeBlock }","tryCatchPattern":"if err := tx.removeAttributeViewField(op); err != nil {\n    if err.Error() == \"cannot remove primary key field\" {\n        // hide column in view instead of deleting\n        return nil\n    }\n    return err\n}","preventionTips":["Always read key.Type before issuing removeAttrViewColumn","Treat the block-type column as immutable; operate on view columns for visibility changes","Favor the official frontend/plugin APIs, which already filter out the primary key"],"tags":["database","attribute-view","primary-key","validation"],"backgroundTag":"unsupported-operation","analyzedSha":"9f775e8a12daef8255556097396f9b2739078892","analyzedAt":"2026-09-19T03:17:15.984Z","contentChangedAt":"2026-09-19T03:17:15.984Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}