Attribute key error

I am getting the following error when processing a Dimension: Errors in the OLAP storage engine: A duplicate attribute key has been found when processing: Table: 'dbo_Orders', Column: 'Project', V...

I am getting the following error when processing a Dimension:

Errors in the OLAP storage engine: A duplicate attribute key has been
found when processing: Table: ‘dbo_Orders’, Column: ‘Project’, Value:
‘client service stuff’. The attribute is ‘Project’.

‘Project’ is an attribute of the ‘Orders’ dimension, but not a key. Nowhere did I indicate that the Project column is a key! I should be able to have as many duplicates as necessary, just like a first name field.

I’m new at Analysis Services project and really need to get past the fact that SSAS is constantly complaining about duplicate values when it should be perfectly OK to have duplicate values. I’m sure this must be something simple that I’m overlooking.

Edit: I realize that it is possible to set KeyDuplicate = ReportAndContinue/ReportAndStop and it is also possible to set KeyColumns and NameColumns. But this multistep process seems very cumbersome for what would seem should be a very normal operation, like adding Address1, Address2, Address3, Firstname, Zipcode, and other fields that normally are duplicated. I can’t believe this cumbersome process need to be applied to all such fields?

user's user avatar

user

4,8165 gold badges17 silver badges35 bronze badges

asked Aug 17, 2011 at 21:40

Dave's user avatar

0

This is usually a result of having both blanks and NULLs in the source table/view.

Essentially, SSAS does this for every attribute
SELECT DISTINCT COALESCE(attr,») FROM SOURCE

Analysis services by default converts NULLs to blanks, resulting in duplicate value blanks in the resulting feed — hence the error.

I agree this sucks and is a major pain for new players.

Solution : Remove all nulls from the data source, for example by using ISNULL / COALESCE everywhere, or filtering out rows containing null using where clause, or running update statement to replace all nulls with values before processing the cube, etc.

answered Sep 1, 2011 at 10:13

WOPR's user avatar

WOPRWOPR

5,2656 gold badges48 silver badges63 bronze badges

9

Right click the attribute and select «Properties». Find «KeyColumn» which is located under the «Source» category within the Properties Window. Edit the «KeyColumn» property, it will display a user friendly window.

Remove the attribute from the right (Key Columns) side of the window and replace it with the actual id column from the left (Available Columns) side.

Then edit the «NameColumn» property, the same window will appear. Move the attribute column (the actual data you want to display) from the left side to the right.

Tested in VS 2010 Shell SSDT.

answered Feb 13, 2013 at 20:41

Eric W.'s user avatar

Eric W.Eric W.

6,5683 gold badges19 silver badges27 bronze badges

2

I had the same issue, and there was no blank or NULL values in the attribute.
After some analysis, I found that some strings had line break character on the end. So, if 2 values of the attribute are nearly the same, but one of them has line break character at the end, and the other doesn’t, then SSAS raises “Duplicate attribute key” error.
It can be fixed by removing line break character from the attribute.
I created calculated column with following definition:

REPLACE(REPLACE(ISNULL([AttributeColumn], ''), CHAR(13), ''), CHAR(10), '')

I used this calculated column in the cube, and the error disappeared.

answered Jun 23, 2016 at 12:08

Pavel Sinkevich's user avatar

4

Just had this happen to me today and scratched my head for a while as none of the solutions here worked. Finally solved it and thought I’d add my solution for anyone else googling this error and arriving here just as I did.

In my case it was not NULL and blank strings as I had the [NullProcessing] value already set to «UnknownMember». Rather it was the [Trimming] value, in my case it was set to «Right».

While I know how I solved(?) it I am not 100% as to why, but I assume when SQL Server does it’s SELECT DISTINCT(col) FROM source and the [Trimming] value is set as such, Analysis server later removes among other things tab chars from the end (which RTRIM in SQL Server for example does not) and ends up with duplicates.

So setting [Trimming] to «None» might solve it, since the tabs was data I did not need (my data is parsed/read/entered from external sources) I simply replaced tabs in the column and after that processing of the cube is fine again.

answered Jan 29, 2014 at 11:10

Don's user avatar

DonDon

9,4314 gold badges26 silver badges25 bronze badges

2

While my other solution on this page works (and depending on situations might be more ideal), this is an alternate solution:

Here is a mock up of part of my error:

Column: 'attribute1_name', Value: 'Search String'

I did a quick search for:

SELECT dim_id,
       dim_name,
       dim_attribute1.id,
       dim_attribute1.name,
       dim_attribute2.id,
       dim_attribute2.name
  FROM dim_table
    INNER JOIN dim_attribute1 ON dim.attribute1_id = dim_attribute1.id
    INNER JOIN dim_attribute2 ON dim.attribute2_id = dim_attribute2.id
 WHERE UPPER(dim_attribute1.name) = UPPER('Search String')

It turns out that there were two different entries for dim_attribute1.name which matched this:

  1. Search String
  2. search string

The first solution split them without issue, so it is a working solution (plus the performance bonus). However an alternative (if one wants to keep the text values as keys) is to change the Collation:

Key Columns → Column Name → Source → Collation

To include ‘case sensitive’.

Other similar issues can be white space characters and other easy to not spot subtle changes in the text.

answered Jul 2, 2012 at 14:39

David Halliday's user avatar

1

I had a similar issue today (same error message), for the sake of anyone else getting here with the same problem I put some notes on my wiki: http://www.david-halliday.co.uk/wiki/doku.php?id=databases:oracle&#select_dates_for_ssas_include_hierarchy

My case was SQL (simplified and reworded to defend the innocent):

SELECT dim_id,
       dim_name,
       dim_attribute1.name,
       dim_attribute2.name
  FROM dim_table
    INNER JOIN dim_attribute1 ON dim.attribute1_id = dim_attribute1.id
    INNER JOIN dim_attribute2 ON dim.attribute2_id = dim_attribute2.id

The strange thing was the error was happening for some cases of dim_attribute1_name but not dim_attribute2_name. However this particular case the attribute was exactly the same. In the end the solution was to change the SQL to:

SELECT dim_id,
       dim_name,
       dim_attribute1.id,
       dim_attribute1.name,
       dim_attribute2.id,
       dim_attribute2.name
  FROM dim_table
    INNER JOIN dim_attribute1 ON dim.attribute1_id = dim_attribute1.id
    INNER JOIN dim_attribute2 ON dim.attribute2_id = dim_attribute2.id

Then use in the dimension (hiding the IDs in the list) the id value for the key of the attribute and the name for the name of the attribute. I haven’t seen this before but for some reason it happened here. This solution I believe is better than setting the cube to process ignoring duplicate key errors.

I presume that if one is building a dimension joining tables this will give better performance/reliability. But don’t quote me on that.

answered Jul 2, 2012 at 12:37

David Halliday's user avatar

1

I had the same problem and I found a workaround for it.

Right Click in «Cube» => «Process» => «Change Settings» => «Dimension Key Errors»

Active «User Custom Error Configuration»

Set «Ignore Errors» for this four drop down list
«Key Not Found»
«Duplicated Key»
«Null key converted to unknown»
«Null key not allowed»

The problem with keys will be ignored.

answered Feb 8, 2013 at 9:47

Jeferson Tenorio's user avatar

I got the problem after I had been playing around with adding an ID into the key column of an attribute. I had since removed the key but found that the select statement during processing was still referring to the ID, making the attribute non unique. I couldn’t find a way of resolving this via the attribute properties, so I deleted the whole Dimension and recreated it. This fixed the issue.

answered Apr 3, 2014 at 12:18

Lesley's user avatar

In case it helps other quasi-newbies like me, I’ll outline a solution that I finally figured out after struggling with the “duplicate attribute key” error message while trying to deploy a Date dimension spanning multiple years. The error message indicated, for example, that I had duplicate attribute keys in my CalendarQuarter attribute. That initially confused me because every complete year has four quarters (i.e. 1, 2, 3 & 4) so of course I had duplicates. It finally dawned on me that that was the problem—in other words (and contrary to the title of this thread) the attribute WAS the key. I solved it by adding a “CalendarQuarterKey” named calculation column to my DSV’s Date table to yield unique keys for my CalendarQuarter attribute, e.g. “20171” instead of just “1” for 2017 Q1, “20172” instead of just “2” for 2017 Q2, etc. Ditto with my CalendarMonth attribute: every complete year has twelve months (i.e. 1, 2, 3…,11, 12) so of course I had duplicates there as well. Same solution: I added a “CalendarMonthKey” named calculation column to my DSV’s Date table to yield unique keys for the CalendarMonth attribute, e.g. “201701” instead of just “1” for January 2017, “201702” instead of just “2” for February 2017, etc. Then, I used my new “CalendarQuarterKey” & “CalendarMonthKey” columns as the KeyColumn for my CalendarQuarter and CalendarMonth attributes respectively. This may not be the preferred solution, but it worked for me and I can finally get back to building my cube.

answered Dec 9, 2018 at 21:51

BRW's user avatar

BRWBRW

1851 silver badge9 bronze badges

I solved by specifying the COLLATION on my views on the relational database as follow.

COALESCE([Descrição da Transação],») COLLATE Latin1_General_CI_AI

answered Mar 6, 2013 at 19:18

Vinicius Paluch's user avatar

If your data contains both NULLs and » SSAS give out duplicate attribute key, because it considers NULLs to be ». You don’t have to touch your data to fix this. You can go to your data source view and add a named calculation with expression COALESCE(mycolumn, »), then use that in your dimension instead of the original column. This will fix the problem at the data source view level and the dimension will process fine.

answered Nov 19, 2013 at 14:06

Stefanos Demetriou's user avatar

Lemme give you a workaround if you still want to go ahead with deployment & cube browsing .
Under ‘process cube’ window, change dimension key error settings to custom .
You would be able to seamlessly deploy & browse the cube .
trade-off here is that you might not get the results which you expected.

answered Jan 22, 2014 at 17:37

Nim J's user avatar

Nim JNim J

9332 gold badges9 silver badges15 bronze badges

some time that need composite key in keyColumns to resolve the duplicate attribute key

answered Jan 23, 2014 at 17:36

Abdeloihab Bourassi's user avatar

I’ve run into this error many times for various reasons, but recently encountered a rather obscure cause: the presence of the beta ß character in a text column. Despite the fact that the thousands of unique words in the column used a hodgepodge of every obscure ASCII code under the sun, SSAS choked only while processing column values that included the ß symbol. Nulls, duplicates, trimming and the like were all systematically ruled out. This is in all likelihood related to unfathomable and unsolved issue discussed in the MSDN thread SSAS 2012 duplicate key error with ‘ss’ and ‘ß’, in which SSAS interpreted ß values as ‘ss’ for some inscrutable reason, even when the collation settings were correct. In my case, setting the Collation in the SSAS column properties to match the source column’s collation of SQL_Latin1_General_CP1_CS_AS on the relational side did not fix this; I had to also change the collation for the entire server. This workaround might be painful in certain environments where other columns depend on different collations, but it skirted this issue in my case and allowed me to process the dimension without a hitch. I hope this helps the next person to stumble over the same «gotcha.»

answered May 23, 2018 at 4:44

SQLServerSteve's user avatar

SQLServerSteveSQLServerSteve

3071 gold badge11 silver badges22 bronze badges


Table of Contents

  • Applies to:
  • Introduction
  • Cause and resolution
    • Default attribute key is not unique
    • Hierarchies are not unique at the leaf level
    • Duplicate key is a Null or blank
    • Collation, case-sensitivity, data type, control characters, or data length
    • Process Update succeeds but Process Full fails
    • ROLAP or ByTable processing generate false positives for this error
    • Partitions contain duplicate rows, including duplicate keys.
  • More information

The full error message is “SSAS Error:  Errors in the OLAP storage engine: A duplicate attribute key has been found when processing: Table: <tablename>, Column: <columnname>. Value: <value>. The attribute is <attributename>.”

Applies to: 

SQL Server Analysis Services (all supported versions), tabular and multidimensional models

Introduction

This error occurs during processing, when a duplicate key is found for a given attribute.

Attribute keys are used to uniquely identify each member of an attribute. This is especially important when two or more attributes have the same value. For example, suppose you have two employees with a last name of Smith. In this case, you might want the
attribute key for LastName to be EmployeeID so that each person is considered independently, and imported as separate rows during processing.

The attribute key is set through KeyColumn in the attribute properties page. As the previous example indicates,
KeyColumn can be different from the Name column. The
Name column provides the value seen by the application user (such as LastName), whereas the
KeyColumn is used to resolve ambiguity during processing, when Analysis Services sends SELECT DISTINCT queries to the relational database.

Cause and resolution

The duplicate attribute key error can occur in multiple situations. In many cases, the recommended solution is to change the
KeyColumn by setting it to a unique attribute, or by creating a composite key that results in a unique value when multiple attributes are evaluated as a unit.

Default attribute key is not unique

By default, both the Name and the KeyColumn are based on the same column in the DSV. If that column contains duplicate values, the duplicate key error will occur.

To investigate this error, check the results of the SELECT DISTINCT query that Analysis Services is sending by capturing and running the query yourself.  Most likely, changing the
KeyColumn to a source column that provides unique values is the best resolution. For example, if
EmployeeLastName has duplicates, set the KeyColumn to
EmployeeID
instead.

See
this forum post for tips on how to investigate this error.

Hierarchies are not unique at the leaf level

Often, a hierarchy (such as Year | Month | Day, Country | Province | City, or Category | Subcategory | Product) is not unique at the leaf level. For example, a City might repeat multiple times throughout the data.

To resolve the ambiguity, create a composite key in KeyColumn that includes Country and Province to add context for each city. For example, a city named Redmond exists in both Washington state and Oregon. Creating a composite key that incorporates
state is sufficient to distinguish between each one (USA.Washington.Redmond] and [USA.Oregon.Redmond]).

Note:  Date hierarchies are often subject to the duplicate attribute key error. Be sure to create composite keys at the Day level that specify Year and Month to ensure that keys are unique throughout the table. Always create the composite
key for the lowest level attribute in the hierarchy. In our example, the composite key would be created on City.

See
http://blog.programmingsolution.net/ssas-2008/period-dimension-time-dimension-creation-with-year-month-day-hierarchy/  for more information.

Duplicate key is a Null or blank

When checking for duplicate values, remember that Null or blank values can also be duplicates. If the error message specifies ‘’ for the value, that is an indication that the duplicate key is a null.

 As with the other scenarios previously mentioned, the fix requires changing
KeyColumn
. The Name column, which is what the user sees, can be null, blank, or unknown, but the
KeyColumn should always be set to an attribute that contains unique values.

Remember that Analysis Services processes nulls as blanks for string columns, and zero for numeric columns. If you discover zeros or blanks that you didn’t expect to find, null processing behavior is the reason.

See
this forum post for more information.

Collation, case-sensitivity, data type, control characters, or data length

Analysis Services and the relational database providing the data might have different collations, different settings on case-sensitivity, or different column lengths, truncating values that would otherwise be unique. If you get the duplicate key error, review
these settings to ensure they are not the cause.

  • Data type —
    One post describes how changing a data type from varchar to nvarchar resolved the issue, allowing Unicode characters to be recognized.
  • Case sensitivity at the dimension level – You can configure the dimension for case sensitivity allowed for differences in case to be processed as unique values. To specify case-sensitivity, use the Collation property on the dimension.  See

    this post for screenshots that show the property.

  • Case sensitivity at the database level —
    Chris Webb points out  that conflicting case-sensitivity settings much higher in the chain (between the relational data source and Analysis Services) can also cause the error to occur.
  • Control characters — Last but not least, sometimes an attribute value is included in processing because it is determined to be unique by SSAS, but is in fact only unique by accident. A leading character, trailing space, or

    control character worked its way into the data, creating a nearly identical second instance of that row. The discrepancy is only detected when processing occurs, when the duplicate attribute key error is raised.

Process Update succeeds but Process Full fails

If you get the error under certain processing options, you probably have a legitimate problem (i.e., an actual duplicate key in the data) that should be addressed.

In the forums, you might see posts advocating for changing the ErrorConfiguration property from (Custom) to (Default) as a way to get ProcessFull to succeed. The difference between the two settings is that (Custom) specifies
Report and Stop for duplicate keys, while (Default) specifies IgnoreErrors.

Although it can be tempting to shut the error down, a better solution is to keep the duplicate key error intact, and then identify and address the root cause of the error.

ROLAP or ByTable processing generate false positives for this error

In
this forum post, Akshai Mirchandani explains that the duplicate attribute key error returns false positives if you are using ByTable processing or ROLAP storage. In this situation, turning off
ErrorConfiguration is the right way to go. In Dimension properties, expand
ErrorConfiguration and set KeyDuplicate to IgnoreErrors.

Tip: Sometimes dimension or cube settings are inadvertently set to values that we don’t expect. Check the storage mode just in case. Also, you can learn a valuable diagnostic technique from tlum, who notes in

this forum post: “Turns out MyDimension was unintentionally set to ROLAP when it should be MOLAP. So, it was processing the MyDimension dimension during the Excel query. Once it was flipped to MOLAP the problem went away.”

Partitions contain duplicate rows, including duplicate keys.

If rows overlap, with two or more partitions containing the same row, this error will occur. Check each partition to ensure that attribute keys are unique across the dimension table, not just within each partition.

See
this forum post from Darren Gosbell for more information.

More information

To get more information, see this curated answer:
https://curatedviews.cloudapp.net/4569/how-do-i-prevent-duplicate-attribute-keys-in-a-cube

The following forum posts were referenced in this page. If you have trouble with the links, review this list to get the full URL addresses:

  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/c160584c-7fa1-46c7-ba5c-c9aed53cb719/errors-in-the-olap-storage-engine-a-duplicate-attribute-key-has-been-found-when-processing
  • http://blog.programmingsolution.net/ssas-2008/period-dimension-time-dimension-creation-with-year-month-day-hierarchy/
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/897f576d-1122-4eac-ba24-7f48a0d0d2cb/a-duplicate-attribute-key-has-been-found
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/de39fb04-3723-4bc2-afc2-3090d1e384f2/duplicate-attribute-key-when-processing-an-factdimension
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/3e8c5003-4d00-450a-af97-9fc07fd6a9b6/foreign-characters-causing-a-duplicate-attribute-key-error-how-to-avoid
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/c160584c-7fa1-46c7-ba5c-c9aed53cb719/errors-in-the-olap-storage-engine-a-duplicate-attribute-key-has-been-found-when-processing
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/7c72639b-a050-4243-9f1d-4da906e981d5/a-duplicate-attribute-key-has-been-found-when-processing
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/3E1A2265-1C58-4F9A-91D9-8C5BD9640436
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/79f0b53d-d75d-42c1-a26c-f9b1fa5266f1/the-dreaded-a-duplicate-attribute-key-has-been-found-when-processing
  • http://social.msdn.microsoft.com/Forums/sqlserver/en-US/5189698E-064C-4ED4-BCC0-82FD3029EB0C

Hi All,

I have been working with SSAS for good amount of time. I have this kind of error many times but this error is weird for me. Let  me tell you
scenario clearly. I have a fact table which deals Apps and its Publishers . I have publisher dimension also. In the publisher dimension i have PublisherName column , this column can have NVarchar data. 

When i am processing the cube i came with the error message saying that » AttributeKey cannot be found when processing DimPublisher , Attribute
PublisherName  , value 
株式会社FXトレーディングシステムズ  
«
 

The above name has the trialing space for the publisherName. But i am able to query my Database with this value and able see some records for the
dimension table , by the below query 

select * from  DimPublishers where PublisherCompanyName=N'株式会社FXトレーディングシステムズ  '

I am really surprised to see why SSAS is not able recognize the trailing spaces for the name.  

Same kind of error message even occurred for the
countryName also . Cube failure countryName value is Tokyo        .Here CountryName tokyo has a
tab space after the CountryName. see the SQL query through which i am able to see some records from Database.

select * from  DimPublishers where Country ='Tokyo	'

Note: 1) For the above two attributes the key column of the
dimension is set the same attribute itself. Collations of both                  SQL and AS are set to default collations

2) I Resolved the error by changing the key column of these attributes to Dimension’s Key     attribute which is PusbliherKey. After this change
i am able to process the cube successfully.

But this is not what my attribute members should have .

Can you please help me why SSAS is giving me this error ?

I’m consistently getting variations on this error when I process the cube in my first SSAS project:

Errors in the OLAP storage engine: The attribute key cannot be found
when processing: Table: ‘dbo_Transactions’, Column: ‘TransactionSK’,
Value: ‘68342998’; Table: ‘dbo_Transactions’, Column:
‘TransactionDateTimeUTC’, Value: ‘7625037’. The attribute is
‘Transaction SK’.

The phrase «attribute key cannot be found when processing» gets a number of Google hits, and several hits on Stack Overflow too (1, 2, 3). However, these address broken FKs, NULL values, or duplicate values (e.g., due to inconsistent case sensitivity). None of those situations apply.

There’s just one table here: dbo.Transactions. It has fields TransactionSK and TransactionDateTimeUTC, both INT NOT NULL. As you can guess, the TransactionDateTimeUTC field is an FK to a DateTimes table, but there are no missing records, that’s enforced in ETL and I’ve verified it in SQL.

What else could be causing this error message? Why does it list two fields, TransactionSK and TransactionDateTimeUTC? The similar situations I’ve bumped into so far consistently only reference a single field in the error message.

The table is being updated in near-real-time, including occasional deletions, though the two fields in question are not updated. If a record is removed from the table after SSAS scans one column and before it scans another, will that produce this error? Spot-checking a few problem records, they were not created in the middle of process the cube.

How do I resolve the «Attribute ‘Key’ does not exist» error when I use the Fn::GetAtt function on my resource provider resource in CloudFormation?

Last updated: 2022-09-19

When I use the Fn::GetAtt function on my resource provider in AWS CloudFormation, I receive the following error:

«Attribute ‘Key’ does not exist»

Short description

Resolution

1.    In your organization-service-resource.json file, confirm that the readOnlyProperties definition uses the following format, where Output is a property that’s defined in the properties section. For example:

"readOnlyProperties": [
    "/properties/Output"
],

Note: The organization-service-resource.json format is located in the root directory of your project.

2.    In your ReadHandler, set the property in the model object. For example:

final ResourceModel model = request.getDesiredResourceState();
model.setOutput("abcdxyz");
return ProgressEvent.<ResourceModel, CallbackContext>builder()
    .resourceModel(model)
    .status(OperationStatus.SUCCESS)
    .build();


Did this article help?


Do you need billing or technical support?

AWS support for Internet Explorer ends on 07/31/2022. Supported browsers are Chrome, Firefox, Edge, and Safari.
Learn more »

Python выводит трассировку (далее traceback), когда в вашем коде появляется ошибка. Вывод traceback может быть немного пугающим, если вы видите его впервые, или не понимаете, чего от вас хотят. Однако traceback Python содержит много информации, которая может помочь вам определить и исправить причину, из-за которой в вашем коде возникла ошибка.

Содержание статьи

  • Traceback — Что это такое и почему оно появляется?
  • Как правильно читать трассировку?
  • Обзор трассировка Python
  • Подробный обзор трассировки в Python
  • Обзор основных Traceback исключений в Python
  • AttributeError
  • ImportError
  • IndexError
  • KeyError
  • NameError
  • SyntaxError
  • TypeError
  • ValueError
  • Логирование ошибок из Traceback
  • Вывод

Понимание того, какую информацию предоставляет traceback Python является основополагающим критерием того, как стать лучшим Python программистом.

К концу данной статьи вы сможете:

  • Понимать, что несет за собой traceback
  • Различать основные виды traceback
  • Успешно вести журнал traceback, при этом исправить ошибку

Python Traceback — Как правильно читать трассировку?

Traceback (трассировка) — это отчет, который содержит вызовы выполненных функций в вашем коде в определенный момент.

Есть вопросы по Python?

На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!

Telegram Чат & Канал

Вступите в наш дружный чат по Python и начните общение с единомышленниками! Станьте частью большого сообщества!

Паблик VK

Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!

Traceback называют по разному, иногда они упоминаются как трассировка стэка, обратная трассировка, и так далее. В Python используется определение “трассировка”.

Когда ваша программа выдает ошибку, Python выводит текущую трассировку, чтобы подсказать вам, что именно пошло не так. Ниже вы увидите пример, демонстрирующий данную ситуацию:

def say_hello(man):

    print(‘Привет, ‘ + wrong_variable)

say_hello(‘Иван’)

Здесь say_hello() вызывается с параметром man. Однако, в say_hello() это имя переменной не используется. Это связано с тем, что оно написано по другому: wrong_variable в вызове print().

Обратите внимание: в данной статье подразумевается, что вы уже имеете представление об ошибках Python. Если это вам не знакомо, или вы хотите освежить память, можете ознакомиться с нашей статьей: Обработка ошибок в Python

Когда вы запускаете эту программу, вы получите следующую трассировку:

Traceback (most recent call last):

  File «/home/test.py», line 4, in <module>

    say_hello(‘Иван’)

  File «/home/test.py», line 2, in say_hello

    print(‘Привет, ‘ + wrong_variable)

NameError: name ‘wrong_variable’ is not defined

Process finished with exit code 1

Эта выдача из traceback содержит массу информации, которая вам понадобится для определения проблемы. Последняя строка трассировки говорит нам, какой тип ошибки возник, а также дополнительная релевантная информация об ошибке. Предыдущие строки из traceback указывают на код, из-за которого возникла ошибка.

В traceback выше, ошибкой является NameError, она означает, что есть отсылка к какому-то имени (переменной, функции, класса), которое не было определено. В данном случае, ссылаются на имя wrong_variable.

Последняя строка содержит достаточно информации для того, чтобы вы могли решить эту проблему. Поиск переменной wrong_variable, и заменит её атрибутом из функции на man. Однако, скорее всего в реальном случае вы будете иметь дело с более сложным кодом.

Python Traceback — Как правильно понять в чем ошибка?

Трассировка Python содержит массу полезной информации, когда вам нужно определить причину ошибки, возникшей в вашем коде. В данном разделе, мы рассмотрим различные виды traceback, чтобы понять ключевые отличия информации, содержащейся в traceback.

Существует несколько секций для каждой трассировки Python, которые являются крайне важными. Диаграмма ниже описывает несколько частей:

Обзор трассировки Python

В Python лучше всего читать трассировку снизу вверх.

  1. Синее поле: последняя строка из traceback — это строка уведомления об ошибке. Синий фрагмент содержит название возникшей ошибки.
  2. Зеленое поле: после названия ошибки идет описание ошибки. Это описание обычно содержит полезную информацию для понимания причины возникновения ошибки.
  3. Желтое поле: чуть выше в трассировке содержатся различные вызовы функций. Снизу вверх — от самых последних, до самых первых. Эти вызовы представлены двухстрочными вводами для каждого вызова. Первая строка каждого вызова содержит такую информацию, как название файла, номер строки и название модуля. Все они указывают на то, где может быть найден код.
  4. Красное подчеркивание: вторая строка этих вызовов содержит непосредственный код, который был выполнен с ошибкой.

Есть ряд отличий между выдачей трассировок, когда вы запускает код в командной строке, и между запуском кода в REPL. Ниже вы можете видеть тот же код из предыдущего раздела, запущенного в REPL и итоговой выдачей трассировки:

Python 3.7.4 (default, Jul 16 2019, 07:12:58)

[GCC 9.1.0] on linux

Type «help», «copyright», «credits» or «license» for more information.

>>>

>>>

>>> def say_hello(man):

...     print(‘Привет, ‘ + wrong_variable)

...

>>> say_hello(‘Иван’)

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

  File «<stdin>», line 2, in say_hello

NameError: name ‘wrong_variable’ is not defined

Обратите внимание на то, что на месте названия файла вы увидите <stdin>. Это логично, так как вы выполнили код через стандартный ввод. Кроме этого, выполненные строки кода не отображаются в traceback.

Важно помнить: если вы привыкли видеть трассировки стэка в других языках программирования, то вы обратите внимание на явное различие с тем, как выглядит traceback в Python. Большая часть других языков программирования выводят ошибку в начале, и затем ведут сверху вниз, от недавних к последним вызовам.

Это уже обсуждалось, но все же: трассировки Python читаются снизу вверх. Это очень помогает, так как трассировка выводится в вашем терминале (или любым другим способом, которым вы читаете трассировку) и заканчивается в конце выдачи, что помогает последовательно структурировать прочтение из traceback и понять в чем ошибка.

Traceback в Python на примерах кода

Изучение отдельно взятой трассировки поможет вам лучше понять и увидеть, какая информация в ней вам дана и как её применить.

Код ниже используется в примерах для иллюстрации информации, данной в трассировке Python:

Мы запустили ниже предоставленный код в качестве примера и покажем какую информацию мы получили от трассировки.

Сохраняем данный код в файле greetings.py

def who_to_greet(person):

    return person if person else input(‘Кого приветствовать? ‘)

def greet(someone, greeting=‘Здравствуйте’):

    print(greeting + ‘, ‘ + who_to_greet(someone))

def greet_many(people):

    for person in people:

        try:

            greet(person)

        except Exception:

            print(‘Привет, ‘ + person)

Функция who_to_greet() принимает значение person и либо возвращает данное значение если оно не пустое, либо запрашивает  значение от пользовательского ввода через input().

Далее, greet() берет имя для приветствия из someone, необязательное значение из greeting и вызывает print(). Также с переданным значением из someone вызывается who_to_greet().

Наконец, greet_many() выполнит итерацию по списку людей и вызовет greet(). Если при вызове greet() возникает ошибка, то выводится резервное приветствие print('hi, ' + person).

Этот код написан правильно, так что никаких ошибок быть не может при наличии правильного ввода.

Если вы добавите вызов функции greet() в конце нашего кода (которого сохранили в файл greetings.py) и дадите аргумент который он не ожидает (например, greet('Chad', greting='Хай')), то вы получите следующую трассировку:

$ python greetings.py

Traceback (most recent call last):

  File «/home/greetings.py», line 19, in <module>

    greet(‘Chad’, greting=‘Yo’)

TypeError: greet() got an unexpected keyword argument ‘greting’

Еще раз, в случае с трассировкой Python, лучше анализировать снизу вверх. Начиная с последней строки трассировки, вы увидите, что ошибкой является TypeError. Сообщения, которые следуют за типом ошибки, дают вам полезную информацию. Трассировка сообщает, что greet() вызван с аргументом, который не ожидался. Неизвестное название аргумента предоставляется в том числе, в нашем случае это greting.

Поднимаясь выше, вы можете видеть строку, которая привела к исключению. В данном случае, это вызов greet(), который мы добавили в конце greetings.py.

Следующая строка дает нам путь к файлу, в котором лежит код, номер строки этого файла, где вы можете найти код, и то, какой в нем модуль. В нашем случае, так как наш код не содержит никаких модулей Python, мы увидим только надпись , означающую, что этот файл является выполняемым.

С другим файлом и другим вводом, вы можете увидеть, что трассировка явно указывает вам на правильное направление, чтобы найти проблему. Следуя этой информации, мы удаляем злополучный вызов greet() в конце greetings.py, и добавляем следующий файл под названием example.py в папку:

from greetings import greet

greet(1)

Здесь вы настраиваете еще один файл Python, который импортирует ваш предыдущий модуль greetings.py, и используете его greet(). Вот что произойдете, если вы запустите example.py:

$ python example.py

Traceback (most recent call last):

  File «/path/to/example.py», line 3, in <module>

    greet(1)

  File «/path/to/greetings.py», line 5, in greet

    print(greeting + ‘, ‘ + who_to_greet(someone))

TypeError: must be str, not int

В данном случае снова возникает ошибка TypeError, но на этот раз уведомление об ошибки не очень помогает. Оно говорит о том, что где-то в коде ожидается работа со строкой, но было дано целое число.

Идя выше, вы увидите строку кода, которая выполняется. Затем файл и номер строки кода. На этот раз мы получаем имя функции, которая была выполнена — greet().

Поднимаясь к следующей выполняемой строке кода, мы видим наш проблемный вызов greet(), передающий целое число.

Иногда, после появления ошибки, другой кусок кода берет эту ошибку и также её выдает. В таких случаях, Python выдает все трассировки ошибки в том порядке, в котором они были получены, и все по тому же принципу, заканчивая на самой последней трассировке.

Так как это может сбивать с толку, рассмотрим пример. Добавим вызов greet_many() в конце greetings.py:

# greetings.py

...

greet_many([‘Chad’, ‘Dan’, 1])

Это должно привести к выводу приветствия всем трем людям. Однако, если вы запустите этот код, вы увидите несколько трассировок в выдаче:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

$ python greetings.py

Hello, Chad

Hello, Dan

Traceback (most recent call last):

  File «greetings.py», line 10, in greet_many

    greet(person)

  File «greetings.py», line 5, in greet

    print(greeting + ‘, ‘ + who_to_greet(someone))

TypeError: must be str, not int

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File «greetings.py», line 14, in <module>

    greet_many([‘Chad’, ‘Dan’, 1])

  File «greetings.py», line 12, in greet_many

    print(‘hi, ‘ + person)

TypeError: must be str, not int

Обратите внимание на выделенную строку, начинающуюся с “During handling in the output above”. Между всеми трассировками, вы ее увидите.

Это достаточно ясное уведомление: Пока ваш код пытался обработать предыдущую ошибку, возникла новая.

Обратите внимание: функция отображения предыдущих трассировок была добавлена в Python 3. В Python 2 вы можете получать только трассировку последней ошибки.

Вы могли видеть предыдущую ошибку, когда вызывали greet() с целым числом. Так как мы добавили 1 в список людей для приветствия, мы можем ожидать тот же результат. Однако, функция greet_many() оборачивает вызов greet() и пытается в блоке try и except. На случай, если greet() приведет к ошибке, greet_many() захочет вывести приветствие по-умолчанию.

Соответствующая часть greetings.py повторяется здесь:

def greet_many(people):

    for person in people:

        try:

            greet(person)

        except Exception:

            print(‘hi, ‘ + person)

Когда greet() приводит к TypeError из-за неправильного ввода числа, greet_many() обрабатывает эту ошибку и пытается вывести простое приветствие. Здесь код приводит к другой, аналогичной ошибке. Он все еще пытается добавить строку и целое число.

Просмотр всей трассировки может помочь вам увидеть, что стало причиной ошибки. Иногда, когда вы получаете последнюю ошибку с последующей трассировкой, вы можете не увидеть, что пошло не так. В этих случаях, изучение предыдущих ошибок даст лучшее представление о корне проблемы.

Обзор основных Traceback исключений в Python 3

Понимание того, как читаются трассировки Python, когда ваша программа выдает ошибку, может быть очень полезным навыком, однако умение различать отдельные трассировки может заметно ускорить вашу работу.

Рассмотрим основные ошибки, с которыми вы можете сталкиваться, причины их появления и что они значат, а также информацию, которую вы можете найти в их трассировках.

Ошибка AttributeError object has no attribute [Решено]

AttributeError возникает тогда, когда вы пытаетесь получить доступ к атрибуту объекта, который не содержит определенного атрибута. Документация Python определяет, когда эта ошибка возникнет:

Возникает при вызове несуществующего атрибута или присвоение значения несуществующему атрибуту.

Пример ошибки AttributeError:

>>> an_int = 1

>>> an_int.an_attribute

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

AttributeError: ‘int’ object has no attribute ‘an_attribute’

Строка уведомления об ошибке для AttributeError говорит вам, что определенный тип объекта, в данном случае int, не имеет доступа к атрибуту, в нашем случае an_attribute. Увидев AttributeError в строке уведомления об ошибке, вы можете быстро определить, к какому атрибуту вы пытались получить доступ, и куда перейти, чтобы это исправить.

Большую часть времени, получение этой ошибки определяет, что вы возможно работаете с объектом, тип которого не является ожидаемым:

>>> a_list = (1, 2)

>>> a_list.append(3)

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

AttributeError: ‘tuple’ object has no attribute ‘append’

В примере выше, вы можете ожидать, что a_list будет типом списка, который содержит метод .append(). Когда вы получаете ошибку AttributeError, и видите, что она возникла при попытке вызова .append(), это говорит о том, что вы, возможно, не работаете с типом объекта, который ожидаете.

Часто это происходит тогда, когда вы ожидаете, что объект вернется из вызова функции или метода и будет принадлежать к определенному типу, но вы получаете тип объекта None. В данном случае, строка уведомления об ошибке будет выглядеть так:

AttributeError: ‘NoneType’ object has no attribute ‘append’

Python Ошибка ImportError: No module named [Решено]

ImportError возникает, когда что-то идет не так с оператором import. Вы получите эту ошибку, или ее подкласс ModuleNotFoundError, если модуль, который вы хотите импортировать, не может быть найден, или если вы пытаетесь импортировать что-то, чего не существует во взятом модуле. Документация Python определяет, когда возникает эта ошибка:

Ошибка появляется, когда в операторе импорта возникают проблемы при попытке загрузить модуль. Также вызывается, при конструкции импорта from list в from ... import имеет имя, которое невозможно найти.

Вот пример появления ImportError и ModuleNotFoundError:

>>> import asdf

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

ModuleNotFoundError: No module named ‘asdf’

>>> from collections import asdf

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

ImportError: cannot import name ‘asdf’

В примере выше, вы можете видеть, что попытка импорта модуля asdf, который не существует, приводит к ModuleNotFoundError. При попытке импорта того, что не существует (в нашем случае — asdf) из модуля, который существует (в нашем случае — collections), приводит к ImportError. Строки сообщения об ошибке трассировок указывают на то, какая вещь не может быть импортирована, в обоих случаях это asdf.

Ошибка IndexError: list index out of range [Решено]

IndexError возникает тогда, когда вы пытаетесь вернуть индекс из последовательности, такой как список или кортеж, и при этом индекс не может быть найден в последовательности. Документация Python определяет, где эта ошибка появляется:

Возникает, когда индекс последовательности находится вне диапазона.

Вот пример, который приводит к IndexError:

>>> a_list = [‘a’, ‘b’]

>>> a_list[3]

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

IndexError: list index out of range

Строка сообщения об ошибке для IndexError не дает вам полную информацию. Вы можете видеть, что у вас есть отсылка к последовательности, которая не доступна и то, какой тип последовательности рассматривается, в данном случае это список.

Иными словами, в списке a_list нет значения с ключом 3. Есть только значение с ключами 0 и 1, это a и b соответственно.

Эта информация, в сочетании с остальной трассировкой, обычно является исчерпывающей для помощи программисту в быстром решении проблемы.

Возникает ошибка KeyError в Python 3 [Решено]

Как и в случае с IndexError, KeyError возникает, когда вы пытаетесь получить доступ к ключу, который отсутствует в отображении, как правило, это dict. Вы можете рассматривать его как IndexError, но для словарей. Из документации:

Возникает, когда ключ словаря не найден в наборе существующих ключей.

Вот пример появления ошибки KeyError:

>>> a_dict = [‘a’: 1, ‘w’: ‘2’]

>>> a_dict[‘b’]

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

KeyError: ‘b’

Строка уведомления об ошибки KeyError говорит о ключе, который не может быть найден. Этого не то чтобы достаточно, но, если взять остальную часть трассировки, то у вас будет достаточно информации для решения проблемы.

Ошибка NameError: name is not defined в Python [Решено]

NameError возникает, когда вы ссылаетесь на название переменной, модуля, класса, функции, и прочего, которое не определено в вашем коде.

Документация Python дает понять, когда возникает эта ошибка NameError:

Возникает, когда локальное или глобальное название не было найдено.

В коде ниже, greet() берет параметр person. Но в самой функции, этот параметр был назван с ошибкой, persn:

>>> def greet(person):

...     print(f‘Hello, {persn}’)

>>> greet(‘World’)

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

  File «<stdin>», line 2, in greet

NameError: name ‘persn’ is not defined

Строка уведомления об ошибке трассировки NameError указывает вам на название, которое мы ищем. В примере выше, это названная с ошибкой переменная или параметр функции, которые были ей переданы.

NameError также возникнет, если берется параметр, который мы назвали неправильно:

>>> def greet(persn):

...     print(f‘Hello, {person}’)

>>> greet(‘World’)

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

  File «<stdin>», line 2, in greet

NameError: name ‘person’ is not defined

Здесь все выглядит так, будто вы сделали все правильно. Последняя строка, которая была выполнена, и на которую ссылается трассировка выглядит хорошо.

Если вы окажетесь в такой ситуации, то стоит пройтись по коду и найти, где переменная person была использована и определена. Так вы быстро увидите, что название параметра введено с ошибкой.

Ошибка SyntaxError: invalid syntax в Python [Решено]

Возникает, когда синтаксический анализатор обнаруживает синтаксическую ошибку.

Ниже, проблема заключается в отсутствии двоеточия, которое должно находиться в конце строки определения функции. В REPL Python, эта ошибка синтаксиса возникает сразу после нажатия Enter:

>>> def greet(person)

  File «<stdin>», line 1

    def greet(person)

                    ^

SyntaxError: invalid syntax

Строка уведомления об ошибке SyntaxError говорит вам только, что есть проблема с синтаксисом вашего кода. Просмотр строк выше укажет вам на строку с проблемой. Каретка ^ обычно указывает на проблемное место. В нашем случае, это отсутствие двоеточия в операторе def нашей функции.

Стоит отметить, что в случае с трассировками SyntaxError, привычная первая строка Tracebak (самый последний вызов) отсутствует. Это происходит из-за того, что SyntaxError возникает, когда Python пытается парсить ваш код, но строки фактически не выполняются.

Ошибка TypeError в Python 3 [Решено]

TypeError возникает, когда ваш код пытается сделать что-либо с объектом, который не может этого выполнить, например, попытка добавить строку в целое число, или вызвать len() для объекта, в котором не определена длина.

Ошибка возникает, когда операция или функция применяется к объекту неподходящего типа.

Рассмотрим несколько примеров того, когда возникает TypeError:

>>> 1 + ‘1’

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

TypeError: unsupported operand type(s) for +: ‘int’ and ‘str’

>>> ‘1’ + 1

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

TypeError: must be str, not int

>>> len(1)

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

TypeError: object of type ‘int’ has no len()

Указанные выше примеры возникновения TypeError приводят к строке уведомления об ошибке с разными сообщениями. Каждое из них весьма точно информирует вас о том, что пошло не так.

В первых двух примерах мы пытаемся внести строки и целые числа вместе. Однако, они немного отличаются:

  • В первом примере мы пытаемся добавить str к int.
  • Во втором примере мы пытаемся добавить int к str.

Уведомления об ошибке указывают на эти различия.

Последний пример пытается вызвать len() для int. Сообщение об ошибке говорит нам, что мы не можем сделать это с int.

Возникла ошибка ValueError в Python 3 [Решено]

ValueError возникает тогда, когда значение объекта не является корректным. Мы можем рассматривать это как IndexError, которая возникает из-за того, что значение индекса находится вне рамок последовательности, только ValueError является более обобщенным случаем.

Возникает, когда операция или функция получает аргумент, который имеет правильный тип, но неправильное значение, и ситуация не описывается более детальной ошибкой, такой как IndexError.

Вот два примера возникновения ошибки ValueError:

>>> a, b, c = [1, 2]

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

ValueError: not enough values to unpack (expected 3, got 2)

>>> a, b = [1, 2, 3]

Traceback (most recent call last):

  File «<stdin>», line 1, in <module>

ValueError: too many values to unpack (expected 2)

Строка уведомления об ошибке ValueError в данных примерах говорит нам в точности, в чем заключается проблема со значениями:

  1. В первом примере, мы пытаемся распаковать слишком много значений. Строка уведомления об ошибке даже говорит нам, где именно ожидается распаковка трех значений, но получаются только два.
  2. Во втором примере, проблема в том, что мы получаем слишком много значений, при этом получаем недостаточно значений для распаковки.

Логирование ошибок из Traceback в Python 3

Получение ошибки, и ее итоговой трассировки указывает на то, что вам нужно предпринять для решения проблемы. Обычно, отладка кода — это первый шаг, но иногда проблема заключается в неожиданном, или некорректном вводе. Хотя важно предусматривать такие ситуации, иногда есть смысл скрывать или игнорировать ошибку путем логирования traceback.

Рассмотрим жизненный пример кода, в котором нужно заглушить трассировки Python. В этом примере используется библиотека requests.

Файл urlcaller.py:

import sys

import requests

response = requests.get(sys.argv[1])

print(response.status_code, response.content)

Этот код работает исправно. Когда вы запускаете этот скрипт, задавая ему URL в качестве аргумента командной строки, он откроет данный URL, и затем выведет HTTP статус кода и содержимое страницы (content) из response. Это работает даже в случае, если ответом является статус ошибки HTTP:

$ python urlcaller.py https://httpbin.org/status/200

200 b»

$ python urlcaller.py https://httpbin.org/status/500

500 b»

Однако, иногда данный URL не существует (ошибка 404 — страница не найдена), или сервер не работает. В таких случаях, этот скрипт приводит к ошибке ConnectionError и выводит трассировку:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

$ python urlcaller.py http://thisurlprobablydoesntexist.com

...

During handling of the above exception, another exception occurred:

Traceback (most recent call last):

  File «urlcaller.py», line 5, in <module>

    response = requests.get(sys.argv[1])

  File «/path/to/requests/api.py», line 75, in get

    return request(‘get’, url, params=params, **kwargs)

  File «/path/to/requests/api.py», line 60, in request

    return session.request(method=method, url=url, **kwargs)

  File «/path/to/requests/sessions.py», line 533, in request

    resp = self.send(prep, **send_kwargs)

  File «/path/to/requests/sessions.py», line 646, in send

    r = adapter.send(request, **kwargs)

  File «/path/to/requests/adapters.py», line 516, in send

    raise ConnectionError(e, request=request)

requests.exceptions.ConnectionError: HTTPConnectionPool(host=‘thisurlprobablydoesntexist.com’, port=80): Max retries exceeded with url: / (Caused by NewConnectionError(‘<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known’,))

Трассировка Python в данном случае может быть очень длинной, и включать в себя множество других ошибок, которые в итоге приводят к ошибке ConnectionError. Если вы перейдете к трассировке последних ошибок, вы заметите, что все проблемы в коде начались на пятой строке файла urlcaller.py.

Если вы обернёте неправильную строку в блоке try и except, вы сможете найти нужную ошибку, которая позволит вашему скрипту работать с большим числом вводов:

Файл urlcaller.py:

try:

    response = requests.get(sys.argv[1])

except requests.exceptions.ConnectionError:

    print(1, ‘Connection Error’)

else:

    print(response.status_code, response.content)

Код выше использует предложение else с блоком except.

Теперь, когда вы запускаете скрипт на URL, который приводит к ошибке ConnectionError, вы получите -1 в статусе кода и содержимое ошибки подключения:

$ python urlcaller.py http://thisurlprobablydoesntexist.com

1 Connection Error

Это работает отлично. Однако, в более реалистичных системах, вам не захочется просто игнорировать ошибку и итоговую трассировку, вам скорее понадобиться внести в журнал. Ведение журнала трассировок позволит вам лучше понять, что идет не так в ваших программах.

Обратите внимание: Для более лучшего представления о системе логирования в Python вы можете ознакомиться с данным руководством тут: Логирование в Python

Вы можете вести журнал трассировки в скрипте, импортировав пакет logging, получить logger, вызвать .exception() для этого логгера в куске except блока try и except. Конечный скрипт будет выглядеть примерно так:

# urlcaller.py

import logging

import sys

import requests

logger = logging.getLogger(__name__)

try:

    response = requests.get(sys.argv[1])

except requests.exceptions.ConnectionError as e:

    logger.exception()

    print(1, ‘Connection Error’)

else:

    print(response.status_code, response.content)

Теперь, когда вы запускаете скрипт с проблемным URL, он будет выводить исключенные -1 и ConnectionError, но также будет вести журнал трассировки:

$ python urlcaller.py http://thisurlprobablydoesntexist.com

...

  File «/path/to/requests/adapters.py», line 516, in send

    raise ConnectionError(e, request=request)

requests.exceptions.ConnectionError: HTTPConnectionPool(host=‘thisurlprobablydoesntexist.com’, port=80): Max retries exceeded with url: / (Caused by NewConnectionError(‘<urllib3.connection.HTTPConnection object at 0x7faf9d671860>: Failed to establish a new connection: [Errno -2] Name or service not known’,))

1 Connection Error

По умолчанию, Python будет выводить ошибки в стандартный stderr. Выглядит так, будто мы совсем не подавили вывод трассировки. Однако, если вы выполните еще один вызов при перенаправлении stderr, вы увидите, что система ведения журналов работает, и мы можем изучать логи программы без необходимости личного присутствия во время появления ошибок:

$ python urlcaller.py http://thisurlprobablydoesntexist.com 2> mylogs.log

1 Connection Error

Подведем итоги данного обучающего материала

Трассировка Python содержит замечательную информацию, которая может помочь вам понять, что идет не так с вашим кодом Python. Эти трассировки могут выглядеть немного запутанно, но как только вы поймете что к чему, и увидите, что они в себе несут, они могут быть предельно полезными. Изучив несколько трассировок, строку за строкой, вы получите лучшее представление о предоставляемой информации.

Понимание содержимого трассировки Python, когда вы запускаете ваш код может быть ключом к улучшению вашего кода. Это способ, которым Python пытается вам помочь.

Теперь, когда вы знаете как читать трассировку Python, вы можете выиграть от изучения ряда инструментов и техник для диагностики проблемы, о которой вам сообщает трассировка. Модуль traceback может быть полезным, если вам нужно узнать больше из выдачи трассировки.

  • Текст является переводом статьи: Understanding the Python Traceback
  • Изображение из шапки статьи принадлежит сайту © Real Python

Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.

E-mail: vasile.buldumac@ati.utm.md

Образование
Universitatea Tehnică a Moldovei (utm.md)

  • 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
  • 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»
Introduction – Part 1

The most common and dreaded error that may occur when processing a dimension in Analysis Services Multidimensional (MD) is undoubtedly “Errors in the OLAP storage engine: A duplicate attribute key has been found when processing: Table: …. “   ‘Common’ because of both the poor data integrity frequently found in cube data sources, and improper modeling of the data in MD. ‘Dreaded’ because a number of distinct situations all give rise to this error and it can be difficult to diagnose which one is the actual problem. There is enough to explore around this error that this is Part 1.  There will be a Part 2 subsequently.

The full error message looks like “Errors in the OLAP storage engine: A duplicate attribute key has been found when processing: Table: ‘TABLENAME’, Column: ‘COLUMN’, Value: ‘VALUE’. The attribute is ‘ATTRIBUTE’.”  TABLENAME will be a concatenation of the Schema and Name properties of the dimension table (separated by “_”) as defined in the Data Source View (DSV) – note it will not be the Friendly Name property of the table which appears in the graphical displays of the DSV and dimension editor. This is the first point of confusion, if the Friendly Name property has been used to give better names to source tables. ATTRIBUTE will be the name of the dimension attribute raising the error, COLUMN will be the name of the relational column of the dimension table on which the attribute is based, and VALUE will be the value of the attribute that is raising the duplicate key error.

Before diving in, it’s worth mentioning that Analysis Services Tabular (Tab) will never raise this error – it will happily ingest and use the same data. Whether this leads to incorrect results or not depends on a number of factors outside the scope of this article. In general, MD is much stricter about data integrity than Tabular, which may be good or bad, depending on your goals and needs.

Case Study Prerequisites

It is assumed the reader has access to and permissions on SQL Server, Analysis Services MD and a compatible version of Visual Studio (VS), with either BIDS or SQL Server Data Tools (SSDT) as appropriate to your version of VS and MD – and sufficient familiarity with all of these to carry out the indicated demos with a minimum of guidance. The demos should work on any version of SQL Server and any version of Analysis Services MD 2005 or later.

To focus as exclusively and simply on the issues as possible, test dimension tables are created and updated in TEMPDB on SQL Server, and modeled as dimensions in a cube database consisting of only the test dimensions (no measure groups) – rather than the traditional Adventure Works database and cube.

Case 1 – Blanks and Nulls in Attribute Key Data

This is the simplest and most common scenario. Simple as it is, much can be learned from it. The duplicate key error will occur when all of the following are true for an attribute:

  1. its KeyColumn property is a column in the source which is nullable
  2. this KeyColumn column becomes a WChar data type in MD
  3. the NullProcessing property is set to “Automatic” (the default)
  4. the NameColumn property is either not defined (shows in BIDS/SSDT as “(none)”), or is explicitly defined as the same column as the KeyColumn property. In both cases the Name values come from the Key column.
  5. a server-generated Unknown member is not defined for the dimension
  6. the Key/Name column contains both nulls and blank/empty strings. If there are no null values, or if there are no blank/empty values, the error will not occur.

Though this may seem like enough different conditions that the issue should arise rarely, in the real world all six conditions are met quite frequently.

Let’s examine the possibilities. Start by executing the following TSQL to create and populate the test dimension table. This is about the simplest dimension possible, with a surrogate key, code field and code description field. Note that the Descr column allows nulls, and has multiple instances of empty string value but no nulls.

Tempdb is used because a very low level of SQL Server permissions is required.

create table tempdb..MD_Dupe_Case1
(
SK     int                  not null,
Code   char(1)              not null,
Descr  varchar(15)
)
go
 
insert tempdb..MD_Dupe_Case1
values
(1, ‘A’, ‘Value1’),
(2, ‘B’, ‘Value2’),
(3, ‘C’, ”),
(4, ‘D’, ”)
go

Next, create a new Multidimensional project in Visual Studio and create a dimension of three attributes representing the above dimension table, defining SK as the Key attribute of the dimension, and in each case defining only the KeyColumn property of each attribute. You will of course first need to create a Data Source object pointing to your SQL Server instance, and then import the table into the DSV.

The following is an example of what this should look like, highlighting the Descr attribute:

as-dupe-pic-1

Build and deploy the project, and do a Full process on the dimension. It should be successful. If you browse the Descr attribute you should see a single blank member.

We need to get a better handle on what is really going on – when browsing the attribute, what is “really” behind something displayed as blank ? Let’s run an MDX query in SSMS to see the values for Key and Name of the Descr attribute – along with additional derived measures that test the values, so we are not totally dependent on how our tool displays things. The following MDX query shows whether a given property is “EMPTY” (MD’s equivalent of NULL) and distinguishes empty and non-empty strings. As a side-benefit it shows how the cube sees the “All” member – we will remove this in future queries. Note: since there is no cube and the query window expects one, you must proceed in a particular way to be able to run this query: a) in SSMS, navigate to the cube database you created and highlight it; b) then and only then open a new query window. You will see that the object pane on the left says “Error loading metadata”, but you can still run the query.

WITH MEMBER [Measures].[key] AS '[MD Dupe Case1].[Descr].currentmember.properties("key0")'
MEMBER [Measures].[name] AS '[MD Dupe Case1].[Descr].currentmember.properties("name")'
MEMBER [Measures].[TestKeyForNull] AS CASE WHEN ISEMPTY([Measures].[key]) THEN "Empty" ELSE "Not Empty" END
MEMBER [Measures].[TestKeyForEmptyString] AS CASE WHEN [Measures].[key] = "" THEN "Empty String" ELSE "Not Empty String" END
MEMBER [Measures].[TestNameForNull] AS CASE WHEN ISEMPTY([Measures].[name]) THEN "Empty" ELSE "Not Empty" END
MEMBER [Measures].[TestNameForEmptyString] AS CASE WHEN [Measures].[name] = "" THEN "Empty String" ELSE "Not Empty String" END
SELECT {
[Measures].[key],
[Measures].[name],
[Measures].[TestKeyForNull],
[Measures].[TestKeyForEmptyString],
[Measures].[TestNameForNull],
[Measures].[TestNameForEmptyString]} ON 0,
[MD Dupe Case1].[Descr].members ON 1
FROM [$MD Dupe Case1]

Here is the result:

as-dupe-pic-2

It is unclear what the “(null)” values for “key” and “name”, derived from the attribute’s “key0” and “name” properties signify, since there were no nulls in the source data, TestKeyForNull finds “key” not ISEMPTY, and TestKeyForEmptyString finds it an Empty String.  We’ll just accept this.

Next, run this SQL update:

update tempdb..MD_Dupe_Case1
set Descr = '     '
where SK = 4

Build, deploy and do a Full process on the dimension (hereafter this will be abbreviated BDF). It should again be successful, and again if you browse the Descr attribute you should see a single blank member, thus illustrating that empty strings and non-empty but blank strings are effectively trimmed to the same distinct value, and may coexist with non-empty, non-blank, non-null values. If you also run the prior MDX Query the results will be the same.

Now, run this update, followed by BDF:

update tempdb..MD_Dupe_Case1
set Descr = null
where SK in (3,4)

Once again it will be successful, and when browsing Descr will appear as the earlier cases, thereby illustrating that multiple nulls may coexist with non-empty, non-blank values. Running the MDX Query will also give the same results.

Now let’s see what happens when there exist both nulls and empty/blank strings in the Key column. Run this update, followed by BDF:

update tempdb..MD_Dupe_Case1
set Descr = ''
where SK = 4

The Full process fails with the duplicate key error on the Descr attribute:

as-dupe-pic-3

Since the dimension did not successfully process, it remains in its prior state, and we cannot explore what is going on via MDX queries. We have to deduce what we can from the SQL query issued during the processing of the Descr attribute, which can be found in the Process Progress dialogue window and is shown below (note you will need to explicitly switch to Tempdb to run this):

SELECT DISTINCT [dbo_MD_Dupe_Case1].[Descr] AS [dbo_MD_Dupe_Case1Descr0_0]
FROM [dbo].[MD_Dupe_Case1] AS [dbo_MD_Dupe_Case1]

The result:

as-dupe-pic-4

So why does the error happen ? Recall that the NullProcessing property for this attribute is set to “Automatic”. This setting (as well as ZeroOrBlank, which is equivalent) means MD will convert nulls to empty strings on the WChar data type, such as we have here. When this happens in the above case, there will be two rows equal to empty string. When the column is in the role of attribute key, there is obviously then a duplicate, which MD is not expecting since a DISTINCT was done. This can be seen in the error message in the value given for “Value:”, which is ‘’.

It could be argued that this is a design flaw in MD – it doesn’t seem quite fair to change the data after a DISTINCT and then demand that it still conform to DISTINCT semantics – but that is the behavior.

We won’t demonstrate it, but the analogue to this if the key column is numeric and NullProcessing set to either Automatic or ZeroOrBlank is the value zero. Nulls would be converted to zero and if there were also present “real” zero values, a similar duplicate key error would result.  Interestingly, if you look back at the prior MDX query results you’ll see that “key” for the “All” member is shown as having a value of zero.  That might make one expect that even one “real” zero value for the key would immediately lead to the error, since the “All” member always exists (well, almost always, but we won’t get into that).  However, this is not the case – “real” zeroes don’t conflict with whatever MD uses internally as the “All” key, but mixed nulls and zeroes will get the error.

You now have insight into the likely cause when the duplicate key error occurs and the reported Value is ‘’ or 0. If you are using views in your DSV (you are, aren’t you ?), you can fix the problem by applying a COALESCE to ‘’ or 0 on the relevant column. Or you may wish to look further back into your ETL process or even source data, to see why you are receiving inconsistent data and perhaps fix it upstream.

Unfortunately, when this error happens, MD does not tell us the value of the dimension key (SK here) on the row(s) with the problem. You need to develop your own SQL query on the DSV source to find the rows with nulls.

Case 1 – But wait, there’s more !

First, while the default error configuration for processing will cause it to fail on the first error, this can be changed so that you can get more information in one run – for instance, to identify all attributes in a dimension that have this problem, and/or how many rows for a given attribute have the problem. This is very useful during development, though you wouldn’t want to modify the default fail-on-first error configuration in production.

To change the error configuration, click “Change Settings” on the Processing dialogue, then choose the “Dimension key errors” tab on the next pane. Click “Use custom error configuration”, then “Ignore errors count”, and then change the “Duplicate key” dropdown to “Report and continue”. Now a Full process will report all such errors across all dimensions. Here is what it looks like:

as-dupe-pic-5

Second, what about those other NullProcessing options: Preserve, Error and UnknownMember ? These have the following effects:

  • Preserve: as this suggests, nulls will be preserved rather than raising an error. With our setup thus far and default error configuration, this option will cause processing to succeed again. When you browse the attribute you will see two indistinguishable blank members, one representing the null and one the true blank. This setting does not seem particularly useful.
  • Error: this setting with our setup and default error configuration will cause processing to fail, but with a different message: Errors in the OLAP storage engine: The record was skipped because a null attribute key was encountered. Attribute: Descr of Dimension: MD Dupe Case1 from Database: DupeKeyTests, Record: 2. At first this might appear useful because it gives you a record number, here “2”. However, it is not useful after all, as it is not the unique identifier (SK here) of the failing row, but the ordinal number of the row as presented by the SQL DISTINCT query – an order which is not defined. It does more precisely explain the nature of the error than the message you get with Automatic, which may be useful in some cases.
  • UnknownMember: this will cause nulls to be mapped into the MD-generated unknown member of the dimension, thereby allowing processing to succeed and for the null cases to be represented as a non-blank member according to whatever you configured for the dimension’s unknown member (how to configure this will not be covered as there are many articles on-line for how to do so). Using the MD-generated unknown member may be useful in prototyping but is generally not recommended – it is far preferable to create one or more “real” “unknown” members in the dimension to represent unknown case(s) and have the ETL assign them according to business rules to the fact table.

Third, again we will not demonstrate it, but the null processing options are also settable in the Dimension Usage pane of the cube editor. In the grid, if you click the “-“ on the granularity attribute at the intersection of any dimension and a measure group, then click Advanced on the resulting dialog, the resulting pane will show a Null Processing column with the same options as those defined earlier. If the setting here differs from that on the granularity attribute in the main dimension (usually the Key attribute), you will get a red squiggly on the granularity attribute in the Dimension Usage tab. What is not clear is whether this is merely a warning – i.e. you can override the main setting – or not. For a visualization of this, though not an answer to this question, see here.

Check out Part 2 of the series to learn more on resolving duplicate attribute key errors within Analysis Services Multidimensional!

_________________________________________________________________________________________

 Learn more about SQL Server 2016 and how Tallan can help turn your data into knowledgeable insights and business action.

Понравилась статья? Поделить с друзьями:
  • Attempting to load game with no stored profile как исправить
  • Attempting boot from usb device disk error press any key to restart
  • Attempting boot from hard drive как исправить hp
  • Attempted to teleport to a place that is restricted error code 773 перевод
  • Attempted to teleport to a place that is restricted error code 773 как исправить