I came across this a long time ago in another app and did the same fudge as you did (hid the created tab)
After a bit of twiddling, I found the reason for my Exception after calling .Free - I had failed to adjust the array via SetLength.
Here's my test unit code which may or may not help in your situation:
unit Unit1;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, ComCtrls,
StdCtrls;
type
{ TForm1 }
TForm1 = class(TForm)
Button1: TButton;
PageControl1: TPageControl;
TabSheet1: TTabSheet;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ private declarations }
ExtraTabs:Array of TTabSheet;
public
{ public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.lfm}
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
Var i:Integer;
begin
i:=High(ExtraTabs);
ShowMessageFmt('High before create = %d',[i]);
Inc(i);
SetLength(ExtraTabs,i+1);
ExtraTabs[i]:=TTabSheet.Create(PageControl1);
ExtraTabs[i].Parent:=PageControl1;
ExtraTabs[i].Caption:='New Tab';
ExtraTabs[i].Visible:=TRUE;
i:=High(ExtraTabs);
ShowMessageFmt('High after create = %d',[i]);
end;
procedure TForm1.Button2Click(Sender: TObject);
Var i:Integer;
begin
i:=High(ExtraTabs);
ShowMessageFmt('High before free = %d',[i]);
If i >= 0 then
begin
ExtraTabs[i].Free;
SetLength(ExtraTabs,i);
end;
i:=High(ExtraTabs);
ShowMessageFmt('High after free = %d',[i]);
end;
end.